mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make fixes, improvements, and chibicc python bindings
- python now mixes audio 10x faster - python octal notation is restored - chibicc now builds code 3x faster - chibicc now has help documentation - chibicc can now generate basic python bindings - linenoise now supports some paredit-like features See #141
This commit is contained in:
parent
28997f3acb
commit
7061c79c22
121 changed files with 5272 additions and 1928 deletions
2
Makefile
2
Makefile
|
@ -145,9 +145,9 @@ include third_party/quickjs/quickjs.mk
|
|||
include third_party/lz4cli/lz4cli.mk
|
||||
include third_party/infozip/infozip.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include third_party/python/python.mk
|
||||
include third_party/chibicc/chibicc.mk
|
||||
include third_party/chibicc/test/test.mk
|
||||
include third_party/python/python.mk
|
||||
include tool/build/emucrt/emucrt.mk
|
||||
include tool/build/emubin/emubin.mk
|
||||
include tool/build/build.mk
|
||||
|
|
|
@ -215,7 +215,7 @@ static void Spawn(int os, int fd, long *sp, char *b, struct Elf64_Ehdr *e) {
|
|||
return;
|
||||
}
|
||||
prot = 0;
|
||||
flags = MAP_FIXED;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) {
|
||||
prot |= PROT_READ;
|
||||
}
|
||||
|
@ -229,13 +229,12 @@ static void Spawn(int os, int fd, long *sp, char *b, struct Elf64_Ehdr *e) {
|
|||
}
|
||||
if (p[i].p_memsz > p[i].p_filesz) {
|
||||
if (Mmap(os, p[i].p_vaddr + p[i].p_filesz, p[i].p_memsz - p[i].p_filesz,
|
||||
prot, flags | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) < 0) {
|
||||
prot, flags | MAP_ANONYMOUS, -1, 0) < 0) {
|
||||
Log(os, "bss mmap failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (p[i].p_filesz) {
|
||||
flags |= prot & PROT_WRITE ? MAP_PRIVATE : MAP_SHARED;
|
||||
if (Mmap(os, p[i].p_vaddr, p[i].p_filesz, prot, flags, fd,
|
||||
p[i].p_offset) < 0) {
|
||||
Log(os, "image mmap failed\n");
|
||||
|
|
|
@ -157,7 +157,11 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-functions \
|
||||
-fno-align-jumps \
|
||||
-fno-align-labels \
|
||||
-fno-align-loops
|
||||
-fno-align-loops \
|
||||
-fschedule-insns2 \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
PYFLAGS += \
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/x/x.h"
|
||||
|
||||
#define CTRL(C) ((C) ^ 0b01000000)
|
||||
#define ENABLE_SAFE_PASTE "\e[?2004h"
|
||||
#define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
|
||||
#define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
|
||||
#define PROBE_DISPLAY_SIZE "\e7\e[9979;9979H\e[6n\e8"
|
||||
|
@ -71,6 +72,7 @@ int rawmode(void) {
|
|||
t.c_cflag |= CS8;
|
||||
t.c_iflag |= IUTF8;
|
||||
ioctl(1, TCSETS, &t);
|
||||
write(1, ENABLE_SAFE_PASTE, strlen(ENABLE_SAFE_PASTE));
|
||||
write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING));
|
||||
write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE));
|
||||
return 0;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist2.internal.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -38,7 +39,7 @@ char *replacestr(const char *s, const char *needle, const char *replacement) {
|
|||
nlen = strlen(needle);
|
||||
rlen = strlen(replacement);
|
||||
res_i = 0;
|
||||
res_n = max(left, 32);
|
||||
res_n = MAX(left, 32);
|
||||
if ((res_p = malloc(res_n * sizeof(char)))) {
|
||||
do {
|
||||
if (!(p2 = memmem(p1, left, needle, nlen))) break;
|
||||
|
|
|
@ -26,5 +26,5 @@
|
|||
* @see rounddown2pow()
|
||||
*/
|
||||
unsigned long roundup2pow(unsigned long x) {
|
||||
return x > 1 ? 1ul << (bsrl(x - 1) + 1) : x ? 1 : 0;
|
||||
return x > 1 ? 2ul << bsrl(x - 1) : x ? 1 : 0;
|
||||
}
|
||||
|
|
55
libc/fmt/formatint32.c
Normal file
55
libc/fmt/formatint32.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 32-bit integer to string.
|
||||
*
|
||||
* @param p needs at least 12 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
noinline char *FormatUint32(char p[static 12], uint32_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
do {
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
p[i] = '\0';
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 32-bit integer to string.
|
||||
*
|
||||
* @param p needs at least 12 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
char *FormatInt32(char p[static 12], int32_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
||||
return FormatUint32(p, x);
|
||||
}
|
|
@ -16,6 +16,8 @@ COSMOPOLITAN_C_START_
|
|||
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
|
||||
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
|
||||
|
||||
char *FormatInt32(char[hasatleast 12], int32_t);
|
||||
char *FormatUint32(char[hasatleast 12], uint32_t);
|
||||
char *FormatInt64(char[hasatleast 21], int64_t);
|
||||
char *FormatUint64(char[hasatleast 21], uint64_t);
|
||||
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
|
||||
|
|
|
@ -871,8 +871,11 @@ static size_t __asan_malloc_usable_size(const void *p) {
|
|||
|
||||
static void __asan_deallocate(char *p, long kind) {
|
||||
size_t c, n;
|
||||
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
|
||||
if (__asan_read48(p + c - 8, &n) && n <= c) {
|
||||
if (__asan_is_mapped((intptr_t)p >> 16) &&
|
||||
(((intptr_t)p >> 16) == ((intptr_t)(p - 16) >> 16) ||
|
||||
__asan_is_mapped((intptr_t)(p - 16) >> 16)) &&
|
||||
(c = weaken(dlmalloc_usable_size)(p)) >= 8 &&
|
||||
__asan_read48(p + c - 8, &n) && n <= c) {
|
||||
__asan_poison((uintptr_t)p, c, kind);
|
||||
if (c <= FRAMESIZE) {
|
||||
p = __asan_morgue_add(p);
|
||||
|
@ -881,9 +884,6 @@ static void __asan_deallocate(char *p, long kind) {
|
|||
} else {
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
} else {
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
}
|
||||
|
||||
void __asan_free(void *p) {
|
||||
|
@ -891,6 +891,17 @@ void __asan_free(void *p) {
|
|||
__asan_deallocate(p, kAsanHeapFree);
|
||||
}
|
||||
|
||||
size_t __asan_bulk_free(void *p[], size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (p[i]) {
|
||||
__asan_deallocate(p[i], kAsanHeapFree);
|
||||
p[i] = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *__asan_memalign(size_t align, size_t size) {
|
||||
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
|
||||
}
|
||||
|
@ -1058,6 +1069,7 @@ void __asan_install_malloc_hooks(void) {
|
|||
HOOK(hook_pvalloc, __asan_pvalloc);
|
||||
HOOK(hook_realloc, __asan_realloc);
|
||||
HOOK(hook_memalign, __asan_memalign);
|
||||
HOOK(hook_bulk_free, __asan_bulk_free);
|
||||
HOOK(hook_malloc_trim, __asan_malloc_trim);
|
||||
HOOK(hook_realloc_in_place, __asan_realloc_in_place);
|
||||
HOOK(hook_malloc_usable_size, __asan_malloc_usable_size);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -25,8 +26,9 @@
|
|||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static noinline antiquity void bzero_sse(char *p, size_t n) {
|
||||
noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
@ -41,12 +43,13 @@ static noinline antiquity void bzero_sse(char *p, size_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||
noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
|
||||
} else if (n >= 1024 && X86_HAVE(ERMS)) {
|
||||
asm("rep stosb" : "+D"(p), "+c"(n), "=m"(*(char(*)[n])p) : "a"(0));
|
||||
} else {
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
|
@ -132,6 +135,7 @@ void(bzero)(void *p, size_t n) {
|
|||
uint64_t x;
|
||||
b = p;
|
||||
if (IsTiny()) {
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
|
|||
unsigned u, u0, u1, u2, u3;
|
||||
if (n > 32) {
|
||||
while (n > 16 + 16) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
|
||||
*(const xmm_t *)q) -
|
||||
0xffff)) {
|
||||
n -= 16;
|
||||
p += 16;
|
||||
|
@ -41,11 +41,10 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
|
||||
0xffff)) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
|
||||
*(const xmm_t *)(q + n - 16)) -
|
||||
0xffff)) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -65,14 +64,14 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
|||
unsigned u, u0, u1, u2, u3;
|
||||
if (n > 32) {
|
||||
while (n >= 16 + 64) {
|
||||
u0 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[0], ((const xmm_t *)q)[0]));
|
||||
u1 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[1], ((const xmm_t *)q)[1]));
|
||||
u2 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[2], ((const xmm_t *)q)[2]));
|
||||
u3 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[3], ((const xmm_t *)q)[3]));
|
||||
u0 = __builtin_ia32_pmovmskb128(
|
||||
(((const xmm_t *)p)[0] == ((const xmm_t *)q)[0]));
|
||||
u1 = __builtin_ia32_pmovmskb128(
|
||||
(((const xmm_t *)p)[1] == ((const xmm_t *)q)[1]));
|
||||
u2 = __builtin_ia32_pmovmskb128(
|
||||
(((const xmm_t *)p)[2] == ((const xmm_t *)q)[2]));
|
||||
u3 = __builtin_ia32_pmovmskb128(
|
||||
(((const xmm_t *)p)[3] == ((const xmm_t *)q)[3]));
|
||||
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
|
||||
(uint64_t)u3 << 48;
|
||||
if (w == -1) {
|
||||
|
@ -85,8 +84,8 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
|||
}
|
||||
}
|
||||
while (n > 16 + 16) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
|
||||
*(const xmm_t *)q) -
|
||||
0xffff)) {
|
||||
n -= 16;
|
||||
p += 16;
|
||||
|
@ -97,11 +96,10 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
|
||||
0xffff)) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
|
||||
*(const xmm_t *)(q + n - 16)) -
|
||||
0xffff)) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -149,7 +147,8 @@ int memcmp(const void *a, const void *b, size_t n) {
|
|||
uint32_t k, i, j;
|
||||
uint64_t w, x, y;
|
||||
const unsigned char *p, *q;
|
||||
if ((p = a) == (q = b)) return 0;
|
||||
if ((p = a) == (q = b) || !n) return 0;
|
||||
if ((c = *p - *q)) return c;
|
||||
if (!IsTiny()) {
|
||||
if (n <= 16) {
|
||||
if (n >= 8) {
|
||||
|
|
|
@ -89,8 +89,8 @@ asm("memcpy = memmove\n\t"
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
char *d;
|
||||
size_t i;
|
||||
char *d, *r;
|
||||
const char *s;
|
||||
uint64_t a, b;
|
||||
xmm_t v, w, x, y, V, W, X, Y, wut;
|
||||
|
@ -119,7 +119,10 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
} else if (n) {
|
||||
*d = *s;
|
||||
}
|
||||
} else if (d <= s) {
|
||||
} else {
|
||||
if (IsAsan()) __asan_check(d, n);
|
||||
if (IsAsan()) __asan_check(s, n);
|
||||
if (d <= s) {
|
||||
asm("rep movsb"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "m"(*(char(*)[n])src));
|
||||
|
@ -132,6 +135,7 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "m"(*(char(*)[n])src));
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
switch (n) {
|
||||
|
@ -208,7 +212,6 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
*(xmm_t *)(d + n - 16) = Y;
|
||||
return d;
|
||||
default:
|
||||
r = d;
|
||||
if (d == s) return d;
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
if (d > s) {
|
||||
|
@ -221,12 +224,14 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
*(xmm_t *)(d + n + 16) = w;
|
||||
} while (n >= 32);
|
||||
} else {
|
||||
if (IsAsan()) __asan_check(d, n);
|
||||
if (IsAsan()) __asan_check(s, n);
|
||||
asm("std\n\t"
|
||||
"rep movsb\n\t"
|
||||
"cld"
|
||||
: "=D"(d), "=S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||
: "0"(d + n - 1), "1"(s + n - 1), "m"(*(char(*)[n])s));
|
||||
return r;
|
||||
return dst;
|
||||
}
|
||||
} else {
|
||||
if (IsAsan() || n < 900 || !X86_HAVE(ERMS)) {
|
||||
|
@ -241,10 +246,12 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
s += i;
|
||||
n -= i;
|
||||
} else {
|
||||
if (IsAsan()) __asan_check(d, n);
|
||||
if (IsAsan()) __asan_check(s, n);
|
||||
asm("rep movsb"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||
: "m"(*(char(*)[n])s));
|
||||
return r;
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -278,54 +285,31 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
}
|
||||
asm("sfence");
|
||||
}
|
||||
switch (n) {
|
||||
case 0:
|
||||
return r;
|
||||
case 17 ... 31:
|
||||
__builtin_memcpy(&v, s, 16);
|
||||
__builtin_memcpy(&w, s + n - 16, 16);
|
||||
__builtin_memcpy(d, &v, 16);
|
||||
__builtin_memcpy(d + n - 16, &w, 16);
|
||||
return r;
|
||||
case 9 ... 15:
|
||||
if (n) {
|
||||
if (n >= 16) {
|
||||
v = *(const xmm_t *)s;
|
||||
w = *(const xmm_t *)(s + n - 16);
|
||||
*(xmm_t *)d = v;
|
||||
*(xmm_t *)(d + n - 16) = w;
|
||||
} else if (n >= 8) {
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(&b, s + n - 8, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
__builtin_memcpy(d + n - 8, &b, 8);
|
||||
return r;
|
||||
case 5 ... 7:
|
||||
} else if (n >= 4) {
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(&b, s + n - 4, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
__builtin_memcpy(d + n - 4, &b, 4);
|
||||
return r;
|
||||
case 16:
|
||||
__builtin_memcpy(&v, s, 16);
|
||||
__builtin_memcpy(d, &v, 16);
|
||||
return r;
|
||||
case 8:
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
return r;
|
||||
case 4:
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
return r;
|
||||
case 1:
|
||||
} else if (n >= 2) {
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(&b, s + n - 2, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
__builtin_memcpy(d + n - 2, &b, 2);
|
||||
} else {
|
||||
*d = *s;
|
||||
return r;
|
||||
case 2:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
return r;
|
||||
case 3:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(&b, s + 1, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
__builtin_memcpy(d + 1, &b, 2);
|
||||
return r;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -25,8 +26,9 @@
|
|||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
|
||||
noasan static noinline antiquity 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_check(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
@ -42,13 +44,15 @@ static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
|
|||
return p;
|
||||
}
|
||||
|
||||
microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) {
|
||||
noasan 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};
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
|
||||
} else if (n >= 1024 && X86_HAVE(ERMS)) {
|
||||
asm("rep stosb" : "=D"(t), "+c"(n), "=m"(*(char(*)[n])p) : "0"(p), "a"(c));
|
||||
} else {
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
|
@ -137,6 +141,7 @@ void *memset(void *p, int c, size_t n) {
|
|||
uint64_t x;
|
||||
b = p;
|
||||
if (IsTiny()) {
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
|
||||
return p;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ noasan size_t strlen(const char *s) {
|
|||
unsigned m, k = (uintptr_t)s & 15;
|
||||
const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16);
|
||||
if (IsAsan()) __asan_verify(s, 1);
|
||||
m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*p, z)) >> k << k;
|
||||
while (!m) m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*++p, z));
|
||||
m = __builtin_ia32_pmovmskb128(*p == z) >> k << k;
|
||||
while (!m) m = __builtin_ia32_pmovmskb128(*++p == z);
|
||||
n = (const char *)p + __builtin_ctzl(m) - s;
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
return n;
|
||||
|
|
|
@ -111,6 +111,7 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
|
|||
*
|
||||
* Then it's unpleasant to need to press C-x C-n six times.
|
||||
*/
|
||||
#if 0
|
||||
while ((p2 = memchr(p1, '\n', p3 - p1))) {
|
||||
if (memmem(p1, p2 - p1, ": __asan_", 9) ||
|
||||
memmem(p1, p2 - p1, ": __die", 7)) {
|
||||
|
@ -121,6 +122,7 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* remove racist output from gnu tooling, that can't be disabled
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#define alignas(x) _Alignas(x)
|
||||
|
||||
#define IS2POW(X) (!((X) & ((X)-1)))
|
||||
#define ROUNDUP(X, K) (((X) + (K)-1) & -(K))
|
||||
#define ROUNDDOWN(X, K) ((X) & -(K))
|
||||
#define ABS(X) ((X) >= 0 ? (X) : -(X))
|
||||
|
|
238
libc/mem/arena.c
Normal file
238
libc/mem/arena.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/arena.h"
|
||||
#include "libc/mem/hook/hook.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
#define BASE ((char *)0x30000000)
|
||||
#define LIMIT ((char *)0x50000000)
|
||||
|
||||
#define EXCHANGE(HOOK, SLOT) \
|
||||
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
|
||||
|
||||
static struct Arena {
|
||||
bool once;
|
||||
uint8_t depth;
|
||||
unsigned size;
|
||||
unsigned offset[16];
|
||||
void (*free)(void *);
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*memalign)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void *(*realloc_in_place)(void *, size_t);
|
||||
void *(*valloc)(size_t);
|
||||
void *(*pvalloc)(size_t);
|
||||
int (*malloc_trim)(size_t);
|
||||
size_t (*malloc_usable_size)(const void *);
|
||||
size_t (*bulk_free)(void *[], size_t);
|
||||
} __arena;
|
||||
|
||||
static wontreturn void __arena_die(void) {
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
_exit(83);
|
||||
}
|
||||
|
||||
static wontreturn void __arena_not_implemented(void) {
|
||||
__printf("not implemented");
|
||||
__arena_die();
|
||||
}
|
||||
|
||||
static void __arena_free(void *p) {
|
||||
if (!p) return;
|
||||
assert(__arena.depth);
|
||||
assert((intptr_t)BASE + __arena.offset[__arena.depth - 1] <= (intptr_t)p &&
|
||||
(intptr_t)p < (intptr_t)BASE + __arena.offset[__arena.depth]);
|
||||
}
|
||||
|
||||
static size_t __arena_bulk_free(void *p[], size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (p[i]) __arena_free(p[i]);
|
||||
}
|
||||
bzero(p, n * sizeof(void *));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *__arena_malloc(size_t n) {
|
||||
char *ptr;
|
||||
size_t need, greed;
|
||||
assert(__arena.depth);
|
||||
if (!n) n = 1;
|
||||
if (n < LIMIT - BASE) {
|
||||
need = __arena.offset[__arena.depth] + n;
|
||||
need = ROUNDUP(need, __BIGGEST_ALIGNMENT__);
|
||||
if (UNLIKELY(need > __arena.size)) {
|
||||
greed = __arena.size + 1;
|
||||
do {
|
||||
greed += greed >> 1;
|
||||
greed = ROUNDUP(greed, FRAMESIZE);
|
||||
} while (need > greed);
|
||||
if (greed < LIMIT - BASE &&
|
||||
mmap(BASE + __arena.size, greed - __arena.size,
|
||||
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
|
||||
-1, 0) != MAP_FAILED) {
|
||||
__arena.size = greed;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ptr = BASE + __arena.offset[__arena.depth];
|
||||
__arena.offset[__arena.depth] = need;
|
||||
return ptr;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void *__arena_calloc(size_t n, size_t z) {
|
||||
if (__builtin_mul_overflow(n, z, &n)) n = -1;
|
||||
return __arena_malloc(n);
|
||||
}
|
||||
|
||||
static void *__arena_memalign(size_t a, size_t n) {
|
||||
if (a <= __BIGGEST_ALIGNMENT__) {
|
||||
return __arena_malloc(n);
|
||||
} else {
|
||||
__arena_not_implemented();
|
||||
}
|
||||
}
|
||||
|
||||
static void *__arena_realloc(void *p, size_t n) {
|
||||
if (p) {
|
||||
if (n) {
|
||||
__arena_not_implemented();
|
||||
} else {
|
||||
__arena_free(p);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return __arena_malloc(n);
|
||||
}
|
||||
}
|
||||
|
||||
static int __arena_malloc_trim(size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *__arena_realloc_in_place(void *p, size_t n) {
|
||||
__arena_not_implemented();
|
||||
}
|
||||
|
||||
static void *__arena_valloc(size_t n) {
|
||||
__arena_not_implemented();
|
||||
}
|
||||
|
||||
static void *__arena_pvalloc(size_t n) {
|
||||
__arena_not_implemented();
|
||||
}
|
||||
|
||||
static size_t __arena_malloc_usable_size(const void *p) {
|
||||
__arena_not_implemented();
|
||||
}
|
||||
|
||||
static void __arena_hook(intptr_t *h, intptr_t *f) {
|
||||
intptr_t t;
|
||||
if (h) {
|
||||
t = *h;
|
||||
*h = *f;
|
||||
*f = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void __arena_install(void) {
|
||||
EXCHANGE(hook_free, __arena.free);
|
||||
EXCHANGE(hook_realloc, __arena.realloc);
|
||||
EXCHANGE(hook_realloc, __arena.realloc);
|
||||
EXCHANGE(hook_malloc, __arena.malloc);
|
||||
EXCHANGE(hook_calloc, __arena.calloc);
|
||||
EXCHANGE(hook_memalign, __arena.memalign);
|
||||
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
|
||||
EXCHANGE(hook_valloc, __arena.valloc);
|
||||
EXCHANGE(hook_pvalloc, __arena.pvalloc);
|
||||
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
|
||||
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
|
||||
EXCHANGE(hook_bulk_free, __arena.bulk_free);
|
||||
}
|
||||
|
||||
static void __arena_destroy(void) {
|
||||
if (__arena.depth) {
|
||||
__arena_install();
|
||||
}
|
||||
if (__arena.size) {
|
||||
munmap(BASE, __arena.size);
|
||||
}
|
||||
bzero(&__arena, sizeof(__arena));
|
||||
}
|
||||
|
||||
static void __arena_init(void) {
|
||||
__arena.free = __arena_free;
|
||||
__arena.realloc = __arena_realloc;
|
||||
__arena.realloc = __arena_realloc;
|
||||
__arena.malloc = __arena_malloc;
|
||||
__arena.calloc = __arena_calloc;
|
||||
__arena.memalign = __arena_memalign;
|
||||
__arena.realloc_in_place = __arena_realloc_in_place;
|
||||
__arena.valloc = __arena_valloc;
|
||||
__arena.pvalloc = __arena_pvalloc;
|
||||
__arena.malloc_trim = __arena_malloc_trim;
|
||||
__arena.malloc_usable_size = __arena_malloc_usable_size;
|
||||
__arena.bulk_free = __arena_bulk_free;
|
||||
atexit(__arena_destroy);
|
||||
}
|
||||
|
||||
void __arena_push(void) {
|
||||
if (UNLIKELY(!__arena.once)) {
|
||||
__arena_init();
|
||||
__arena.once = true;
|
||||
}
|
||||
if (!__arena.depth) {
|
||||
__arena_install();
|
||||
} else if (__arena.depth == ARRAYLEN(__arena.offset) - 1) {
|
||||
__printf("too many arenas");
|
||||
__arena_die();
|
||||
}
|
||||
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
|
||||
++__arena.depth;
|
||||
}
|
||||
|
||||
void __arena_pop(void) {
|
||||
unsigned greed;
|
||||
assert(__arena.depth);
|
||||
bzero(BASE + __arena.offset[__arena.depth - 1],
|
||||
__arena.offset[__arena.depth] - __arena.offset[__arena.depth - 1]);
|
||||
if (!--__arena.depth) __arena_install();
|
||||
greed = __arena.offset[__arena.depth];
|
||||
greed += FRAMESIZE;
|
||||
greed <<= 1;
|
||||
if (__arena.size > greed) {
|
||||
munmap(BASE + greed, __arena.size - greed);
|
||||
}
|
||||
}
|
11
libc/mem/arena.h
Normal file
11
libc/mem/arena.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_MEM_ARENA_H_
|
||||
#define COSMOPOLITAN_LIBC_MEM_ARENA_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __arena_push(void);
|
||||
void __arena_pop(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_MEM_ARENA_H_ */
|
30
libc/mem/bulk_free.S
Normal file
30
libc/mem/bulk_free.S
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Frees and clears (sets to NULL) each non-null pointer in given array.
|
||||
//
|
||||
// This is twice as fast as freeing them one-by-one. If footers are
|
||||
// used, pointers that have been allocated in different mspaces are
|
||||
// not freed or cleared, and the count of all such pointers is returned.
|
||||
// For large arrays of pointers with poor locality, it may be worthwhile
|
||||
// to sort this array before calling bulk_free.
|
||||
bulk_free:
|
||||
jmp *hook_bulk_free(%rip)
|
||||
.endfn bulk_free,globl
|
31
libc/mem/hook/bulk_free.S
Normal file
31
libc/mem/hook/bulk_free.S
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.initbss 202,_init_bulk_free
|
||||
hook_bulk_free:
|
||||
.quad 0
|
||||
.endobj hook_bulk_free,globl,hidden
|
||||
.previous
|
||||
|
||||
.init.start 202,_init_bulk_free
|
||||
.hidden dlbulk_free
|
||||
ezlea dlbulk_free,ax
|
||||
stosq
|
||||
.init.end 202,_init_bulk_free
|
|
@ -13,6 +13,7 @@ extern void *(*hook_valloc)(size_t);
|
|||
extern void *(*hook_pvalloc)(size_t);
|
||||
extern int (*hook_malloc_trim)(size_t);
|
||||
extern size_t (*hook_malloc_usable_size)(const void *);
|
||||
extern size_t (*hook_bulk_free)(void *[], size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -101,7 +101,12 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 6 && !defined(__chibicc__)
|
||||
#define EFIAPI __attribute__((__ms_abi__))
|
||||
#else
|
||||
#define EFIAPI /* TODO(jart): fix me */
|
||||
#endif
|
||||
|
||||
#define EFI_STATUS uint64_t
|
||||
#define EFI_EVENT uintptr_t
|
||||
#define EFI_HANDLE uintptr_t
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -40,10 +41,13 @@
|
|||
*
|
||||
* @return original buf
|
||||
*/
|
||||
void *rngset(void *b, size_t n, uint64_t seed(void), size_t reseed) {
|
||||
noasan void *rngset(void *b, size_t n, uint64_t seed(void), size_t reseed) {
|
||||
size_t m;
|
||||
uint64_t i, x, t = 0;
|
||||
unsigned char *p = b;
|
||||
if (IsAsan()) {
|
||||
__asan_check(b, n);
|
||||
}
|
||||
if (!seed) {
|
||||
t = reseed;
|
||||
reseed = -1;
|
||||
|
|
|
@ -29,5 +29,5 @@
|
|||
* @return 0 on success or nonzero if out of space
|
||||
*/
|
||||
int atexit(void f(void)) {
|
||||
return __cxa_atexit(f, NULL, NULL);
|
||||
return __cxa_atexit(f, 0, 0);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
|
|||
* @return 0 on success or nonzero w/ errno
|
||||
* @note folks have forked libc in past just to unbloat atexit()
|
||||
*/
|
||||
int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||
unsigned i;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
/**
|
||||
|
@ -44,8 +46,9 @@
|
|||
*
|
||||
* @see ape/ape.lds
|
||||
*/
|
||||
privileged noinstrument noasan void __hook(void *ifunc,
|
||||
privileged noinstrument noasan int __hook(void *ifunc,
|
||||
struct SymbolTable *symbols) {
|
||||
int rc;
|
||||
size_t i;
|
||||
char *p, *pe;
|
||||
intptr_t addr;
|
||||
|
@ -57,10 +60,10 @@ privileged noinstrument noasan void __hook(void *ifunc,
|
|||
bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
|
||||
sigfillset(&mask);
|
||||
sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
if (mprotect((void *)symbols->addr_base,
|
||||
kPrivilegedStart - symbols->addr_base,
|
||||
if ((rc = mprotect(
|
||||
(void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base,
|
||||
kIsBinaryAligned ? PROT_READ | PROT_WRITE
|
||||
: PROT_READ | PROT_WRITE | PROT_EXEC) != -1) {
|
||||
: PROT_READ | PROT_WRITE | PROT_EXEC)) != -1) {
|
||||
for (i = 0; i < symbols->count; ++i) {
|
||||
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
|
||||
continue;
|
||||
|
@ -125,4 +128,5 @@ privileged noinstrument noasan void __hook(void *ifunc,
|
|||
PROT_READ | PROT_EXEC);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ COSMOPOLITAN_C_START_
|
|||
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
|
||||
#define kAutomapStart MEMTRACK_ADDRESS(_kAutomapStart, 0x10000000)
|
||||
#define kAutomapSize MEMTRACK_ADDRESS(_kAutomapSize, 0x40000000)
|
||||
#define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x40000000)
|
||||
#define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x50000000)
|
||||
|
||||
struct MemoryInterval {
|
||||
int x;
|
||||
|
|
|
@ -26,7 +26,7 @@ const char *FindComBinary(void);
|
|||
const char *FindDebugBinary(void);
|
||||
struct SymbolTable *OpenSymbolTable(const char *);
|
||||
int CloseSymbolTable(struct SymbolTable **);
|
||||
void __hook(void *, struct SymbolTable *);
|
||||
int __hook(void *, struct SymbolTable *);
|
||||
|
||||
forceinline int GetSymbol(struct SymbolTable *t, intptr_t a) {
|
||||
unsigned l, m, r, n, k;
|
||||
|
|
|
@ -17,18 +17,55 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
|
||||
void djbsort_avx2(int32_t *, long);
|
||||
|
||||
static noinline void intsort(int *x, size_t n, size_t t) {
|
||||
int a, b, c;
|
||||
size_t i, p, q;
|
||||
for (p = t; p > 0; p >>= 1) {
|
||||
for (i = 0; i < n - p; ++i) {
|
||||
if (!(i & p)) {
|
||||
a = x[i + 0];
|
||||
b = x[i + p];
|
||||
if (a > b) c = a, a = b, b = c;
|
||||
x[i + 0] = a;
|
||||
x[i + p] = b;
|
||||
}
|
||||
}
|
||||
for (q = t; q > p; q >>= 1) {
|
||||
for (i = 0; i < n - q; ++i) {
|
||||
if (!(i & p)) {
|
||||
a = x[i + p];
|
||||
b = x[i + q];
|
||||
if (a > b) c = a, a = b, b = c;
|
||||
x[i + p] = a;
|
||||
x[i + q] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* D.J. Bernstein's outrageously fast integer sorting algorithm.
|
||||
*/
|
||||
void djbsort(int32_t *a, size_t n) {
|
||||
size_t m;
|
||||
if (IsAsan()) {
|
||||
if (__builtin_mul_overflow(n, 4, &m)) m = -1;
|
||||
__asan_check(a, m);
|
||||
}
|
||||
if (n > 1) {
|
||||
if (X86_HAVE(AVX2)) {
|
||||
djbsort_avx2(a, n);
|
||||
} else {
|
||||
insertionsort(a, n);
|
||||
intsort(a, n, 1ul << bsrl(n - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -390,14 +390,14 @@ static const unsigned kAstralCodes[][2] = {
|
|||
* other things like blocks and emoji (So).
|
||||
*/
|
||||
int iswseparator(wint_t c) {
|
||||
int m, l, r;
|
||||
int m, l, r, n;
|
||||
if (c < 0200) {
|
||||
return !(('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') ||
|
||||
('a' <= c && c <= 'z'));
|
||||
}
|
||||
if (c <= 0xffff) {
|
||||
l = 0;
|
||||
r = sizeof(kCodes) / sizeof(kCodes[0]);
|
||||
r = n = sizeof(kCodes) / sizeof(kCodes[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kCodes[m][1] < c) {
|
||||
|
@ -406,10 +406,10 @@ int iswseparator(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
return !(kCodes[l][0] <= c && c <= kCodes[l][1]);
|
||||
return !(l < n && kCodes[l][0] <= c && c <= kCodes[l][1]);
|
||||
} else {
|
||||
l = 0;
|
||||
r = sizeof(kAstralCodes) / sizeof(kAstralCodes[0]);
|
||||
r = n = sizeof(kAstralCodes) / sizeof(kAstralCodes[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kAstralCodes[m][1] < c) {
|
||||
|
@ -418,6 +418,6 @@ int iswseparator(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
return !(kAstralCodes[l][0] <= c && c <= kAstralCodes[l][1]);
|
||||
return !(l < n && kAstralCodes[l][0] <= c && c <= kAstralCodes[l][1]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "net/http/escape.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
const signed char kHexToInt[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00
|
|
@ -18,12 +18,14 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
forceinline void longsorter(long *x, size_t n, size_t t) {
|
||||
long a, b, c, p, q, i;
|
||||
long a, b, c;
|
||||
size_t i, p, q;
|
||||
for (p = t; p > 0; p >>= 1) {
|
||||
for (i = 0; i < n - p; ++i) {
|
||||
if (!(i & p)) {
|
||||
|
@ -68,7 +70,10 @@ void longsort(long *x, size_t n) {
|
|||
}
|
||||
if (n > 1) {
|
||||
t = 1ul << bsrl(n - 1);
|
||||
if (X86_HAVE(AVX2)) return longsort_avx2(x, n, t);
|
||||
return longsort_pure(x, n, t);
|
||||
if (X86_HAVE(AVX2)) {
|
||||
longsort_avx2(x, n, t);
|
||||
} else {
|
||||
longsort_pure(x, n, t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,38 +54,12 @@ static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
|||
*/
|
||||
void *memccpy(void *dst, const void *src, int c, size_t n) {
|
||||
size_t i;
|
||||
uint64_t v, w;
|
||||
unsigned char *d, *q;
|
||||
unsigned char *d;
|
||||
const unsigned char *s;
|
||||
i = 0;
|
||||
d = dst;
|
||||
s = src;
|
||||
c &= 255;
|
||||
v = 0x0101010101010101ul * c;
|
||||
for (; (uintptr_t)(s + i) & 7; ++i) {
|
||||
if (i == n) return NULL;
|
||||
if ((d[i] = s[i]) == c) return d + i + 1;
|
||||
}
|
||||
for (; i + 8 <= n; i += 8) {
|
||||
w = UncheckedAlignedRead64(s + i);
|
||||
if (~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080) {
|
||||
break;
|
||||
} else {
|
||||
q = d + i;
|
||||
q[0] = (w & 0x00000000000000ff) >> 000;
|
||||
q[1] = (w & 0x000000000000ff00) >> 010;
|
||||
q[2] = (w & 0x0000000000ff0000) >> 020;
|
||||
q[3] = (w & 0x00000000ff000000) >> 030;
|
||||
q[4] = (w & 0x000000ff00000000) >> 040;
|
||||
q[5] = (w & 0x0000ff0000000000) >> 050;
|
||||
q[6] = (w & 0x00ff000000000000) >> 060;
|
||||
q[7] = (w & 0xff00000000000000) >> 070;
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i) {
|
||||
if ((d[i] = s[i]) == c) {
|
||||
for (d = dst, s = src, i = 0; i < n; ++i) {
|
||||
if ((d[i] = s[i]) == (c & 255)) {
|
||||
return d + i + 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,35 +16,64 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
static inline const unsigned char *memchr_pure(const unsigned char *s,
|
||||
unsigned char c, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] == c) {
|
||||
return s + i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
noasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
||||
unsigned char c,
|
||||
size_t n) {
|
||||
size_t i;
|
||||
unsigned k;
|
||||
unsigned m;
|
||||
xmm_t v, *p;
|
||||
xmm_t t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
for (; n >= 16; n -= 16, s += 16) {
|
||||
v = *(const xmm_t *)s;
|
||||
m = __builtin_ia32_pmovmskb128(v == t);
|
||||
if (m) {
|
||||
m = __builtin_ctzll(m);
|
||||
return s + m;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] == c) {
|
||||
return s + i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pointer to first instance of character.
|
||||
*
|
||||
* @param m is memory to search
|
||||
* @param s is memory to search
|
||||
* @param c is search byte which is masked with 255
|
||||
* @param n is byte length of p
|
||||
* @return is pointer to first instance of c or NULL if not found
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void *memchr(const void *m, int c, size_t n) {
|
||||
uint64_t v, w;
|
||||
const char *p, *pe;
|
||||
c &= 255;
|
||||
v = 0x0101010101010101ul * c;
|
||||
for (p = m, pe = p + n; p + 8 <= pe; p += 8) {
|
||||
w = (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
|
||||
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
|
||||
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
|
||||
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
|
||||
if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) {
|
||||
return p + ((unsigned)__builtin_ctzll(w) >> 3);
|
||||
void *memchr(const void *s, int c, size_t n) {
|
||||
const void *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
if (IsAsan()) __asan_check(s, n);
|
||||
r = memchr_sse(s, c, n);
|
||||
} else {
|
||||
r = memchr_pure(s, c, n);
|
||||
}
|
||||
}
|
||||
for (; p < pe; ++p) {
|
||||
if ((*p & 255) == c) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return (void *)r;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,39 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
||||
return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
||||
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
||||
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static inline const unsigned char *rawmemchr_pure(const unsigned char *s,
|
||||
unsigned char c) {
|
||||
for (;; ++s) {
|
||||
if (*s == c) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
noasan static inline const char *rawmemchr_sse(const char *s, unsigned char c) {
|
||||
unsigned k;
|
||||
unsigned m;
|
||||
xmm_t v, *p;
|
||||
xmm_t n = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
k = (uintptr_t)s & 15;
|
||||
p = (const xmm_t *)((uintptr_t)s & -16);
|
||||
v = *p;
|
||||
m = __builtin_ia32_pmovmskb128(v == n);
|
||||
m >>= k;
|
||||
m <<= k;
|
||||
while (!m) {
|
||||
v = *++p;
|
||||
m = __builtin_ia32_pmovmskb128(v == n);
|
||||
}
|
||||
m = __builtin_ctzll(m);
|
||||
return (const char *)p + m;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,22 +59,13 @@ static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
|||
* @param c is search byte which is masked with 255
|
||||
* @return is pointer to first instance of c
|
||||
*/
|
||||
void *rawmemchr(const void *m, int c) {
|
||||
uint64_t v, w;
|
||||
const unsigned char *s;
|
||||
s = m;
|
||||
c &= 255;
|
||||
v = 0x0101010101010101ul * c;
|
||||
for (; (uintptr_t)s & 7; ++s) {
|
||||
if (*s == c) return s;
|
||||
void *rawmemchr(const void *s, int c) {
|
||||
const void *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
if (IsAsan()) __asan_check(s, 1);
|
||||
r = rawmemchr_sse(s, c);
|
||||
} else {
|
||||
r = rawmemchr_pure(s, c);
|
||||
}
|
||||
for (;; s += 8) {
|
||||
w = UncheckedAlignedRead64(s);
|
||||
if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) {
|
||||
s += (unsigned)__builtin_ctzll(w) >> 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(*s == c);
|
||||
return s;
|
||||
return (void *)r;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ COSMOPOLITAN_C_START_
|
|||
╚────────────────────────────────────────────────────────────────────────────│─╝
|
||||
fourth age telecommunications */
|
||||
|
||||
extern const int8_t kHexToInt[256];
|
||||
extern const uint8_t gperf_downcase[256];
|
||||
extern const uint8_t kToLower[256];
|
||||
extern const uint8_t kToUpper[256];
|
||||
|
|
|
@ -17,35 +17,40 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static noasan inline const char *strchr_x64(const char *p, uint64_t c) {
|
||||
unsigned a, b;
|
||||
uint64_t w, x, y;
|
||||
for (c *= 0x0101010101010101;; p += 8) {
|
||||
w = (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
|
||||
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
|
||||
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
|
||||
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
|
||||
if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) |
|
||||
(y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
|
||||
if (x) {
|
||||
a = __builtin_ctzll(x);
|
||||
if (y) {
|
||||
b = __builtin_ctzll(y);
|
||||
if (a <= b) {
|
||||
return p + (a >> 3);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return p + (a >> 3);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static inline const char *strchr_pure(const char *s, int c) {
|
||||
for (;; ++s) {
|
||||
if ((*s & 255) == (c & 255)) return s;
|
||||
if (!*s) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
noasan static inline const char *strchr_sse(const char *s, unsigned char c) {
|
||||
unsigned k;
|
||||
unsigned m;
|
||||
xmm_t v, *p;
|
||||
xmm_t z = {0};
|
||||
xmm_t n = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
k = (uintptr_t)s & 15;
|
||||
p = (const xmm_t *)((uintptr_t)s & -16);
|
||||
v = *p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
m >>= k;
|
||||
m <<= k;
|
||||
while (!m) {
|
||||
v = *++p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
}
|
||||
m = __builtin_ctzl(m);
|
||||
s = (const char *)p + m;
|
||||
if (c && !*s) s = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,12 +63,13 @@ static noasan inline const char *strchr_x64(const char *p, uint64_t c) {
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
char *strchr(const char *s, int c) {
|
||||
char *r;
|
||||
for (c &= 255; (uintptr_t)s & 7; ++s) {
|
||||
if ((*s & 255) == c) return s;
|
||||
if (!*s) return NULL;
|
||||
const char *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
if (IsAsan()) __asan_check(s, 1);
|
||||
r = strchr_sse(s, c);
|
||||
} else {
|
||||
r = strchr_pure(s, c);
|
||||
}
|
||||
r = strchr_x64(s, c);
|
||||
assert(!r || *r || !c);
|
||||
return r;
|
||||
assert(!r || *r || !(c & 255));
|
||||
return (char *)r;
|
||||
}
|
||||
|
|
|
@ -17,36 +17,37 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
noasan static const char *strchrnul_x64(const char *p, uint64_t c) {
|
||||
unsigned a, b;
|
||||
uint64_t w, x, y;
|
||||
for (c *= 0x0101010101010101;; p += 8) {
|
||||
w = (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
|
||||
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
|
||||
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
|
||||
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
|
||||
if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) |
|
||||
(y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
|
||||
if (x) {
|
||||
a = __builtin_ctzll(x);
|
||||
if (y) {
|
||||
b = __builtin_ctzll(y);
|
||||
if (a <= b) {
|
||||
return p + (a >> 3);
|
||||
} else {
|
||||
return p + (b >> 3);
|
||||
}
|
||||
} else {
|
||||
return p + (a >> 3);
|
||||
}
|
||||
} else {
|
||||
b = __builtin_ctzll(y);
|
||||
return p + (b >> 3);
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static inline const char *strchrnul_pure(const char *s, int c) {
|
||||
for (;; ++s) {
|
||||
if ((*s & 255) == (c & 255)) return s;
|
||||
if (!*s) return s;
|
||||
}
|
||||
}
|
||||
|
||||
noasan static inline const char *strchrnul_sse(const char *s, unsigned char c) {
|
||||
unsigned k;
|
||||
unsigned m;
|
||||
xmm_t v, *p;
|
||||
xmm_t z = {0};
|
||||
xmm_t n = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
k = (uintptr_t)s & 15;
|
||||
p = (const xmm_t *)((uintptr_t)s & -16);
|
||||
v = *p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
m >>= k;
|
||||
m <<= k;
|
||||
while (!m) {
|
||||
v = *++p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
}
|
||||
return (const char *)p + __builtin_ctzl(m);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,12 +59,13 @@ noasan 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) {
|
||||
char *r;
|
||||
for (c &= 255; (uintptr_t)s & 7; ++s) {
|
||||
if ((*s & 0xff) == c) return s;
|
||||
if (!*s) return s;
|
||||
const char *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
if (IsAsan()) __asan_check(s, 1);
|
||||
r = strchrnul_sse(s, c);
|
||||
} else {
|
||||
r = strchrnul_pure(s, c);
|
||||
}
|
||||
r = strchrnul_x64(s, c);
|
||||
assert((*r & 255) == c || !*r);
|
||||
return r;
|
||||
assert((*r & 255) == (c & 255) || !*r);
|
||||
return (char *)r;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int strcmp(const char *a, const char *b) {
|
||||
int c;
|
||||
size_t i = 0;
|
||||
uint64_t v, w, d;
|
||||
if (a == b) return 0;
|
||||
if ((c = (*a & 255) - (*b & 255))) return c;
|
||||
if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) {
|
||||
for (; (uintptr_t)(a + i) & 7; ++i) {
|
||||
if (a[i] != b[i] || !b[i]) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/hascharacter.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
@ -24,17 +23,21 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
char *strpbrk(const char *s, const char *accept) {
|
||||
size_t i;
|
||||
bool lut[256];
|
||||
if (accept[0]) {
|
||||
if (!accept[1]) {
|
||||
return strchr(s, accept[0]);
|
||||
} else {
|
||||
for (i = 0; s[i]; ++i) {
|
||||
if (HasCharacter(s[i], accept)) {
|
||||
return (/*unconst*/ char *)&s[i];
|
||||
memset(lut, 0, sizeof(lut));
|
||||
while (*accept) {
|
||||
lut[*accept++ & 255] = true;
|
||||
}
|
||||
for (; *s; ++s) {
|
||||
if (lut[*s & 255]) {
|
||||
return (/*unconst*/ char *)s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,14 +49,12 @@ noasan char *strstr(const char *haystack, const char *needle) {
|
|||
k = (uintptr_t)haystack & 15;
|
||||
p = (const xmm_t *)((uintptr_t)haystack & -16);
|
||||
v = *p;
|
||||
m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(v, z) |
|
||||
__builtin_ia32_pcmpeqb128(v, n));
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
m >>= k;
|
||||
m <<= k;
|
||||
while (!m) {
|
||||
v = *++p;
|
||||
m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(v, z) |
|
||||
__builtin_ia32_pcmpeqb128(v, n));
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == n));
|
||||
}
|
||||
haystack = (const char *)p + __builtin_ctzl(m);
|
||||
for (i = 0;; ++i) {
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef uint64_t xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
static noinline antiquity unsigned timingsafe_bcmp_sse(const char *p,
|
||||
noasan static noinline antiquity unsigned timingsafe_bcmp_sse(const char *p,
|
||||
const char *q,
|
||||
size_t n) {
|
||||
uint64_t w;
|
||||
|
@ -40,7 +41,7 @@ static noinline antiquity unsigned timingsafe_bcmp_sse(const char *p,
|
|||
return w | w >> 32;
|
||||
}
|
||||
|
||||
microarchitecture("avx") static int timingsafe_bcmp_avx(const char *p,
|
||||
noasan static microarchitecture("avx") int timingsafe_bcmp_avx(const char *p,
|
||||
const char *q,
|
||||
size_t n) {
|
||||
uint64_t w;
|
||||
|
@ -134,11 +135,17 @@ int timingsafe_bcmp(const void *a, const void *b, size_t n) {
|
|||
__builtin_memcpy(&w3, q + n - 8, 8);
|
||||
w = (w0 ^ w1) | (w2 ^ w3);
|
||||
return w | w >> 32;
|
||||
} else if (X86_HAVE(AVX)) {
|
||||
} else {
|
||||
if (IsAsan()) {
|
||||
__asan_check(a, n);
|
||||
__asan_check(b, n);
|
||||
}
|
||||
if (X86_HAVE(AVX)) {
|
||||
return timingsafe_bcmp_avx(p, q, n);
|
||||
} else {
|
||||
return timingsafe_bcmp_sse(p, q, n);
|
||||
}
|
||||
}
|
||||
} else if (n >= 4) {
|
||||
__builtin_memcpy(&u0, p, 4);
|
||||
__builtin_memcpy(&u1, q, 4);
|
||||
|
|
|
@ -177,7 +177,7 @@ static const int kAstralLower[][3] = {
|
|||
* Converts wide character to lower case.
|
||||
*/
|
||||
wint_t towlower(wint_t c) {
|
||||
int m, l, r;
|
||||
int m, l, r, n;
|
||||
if (c < 0200) {
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return c + 32;
|
||||
|
@ -199,7 +199,7 @@ wint_t towlower(wint_t c) {
|
|||
return c + 38864; /* 80x Ꭰ ..Ꮿ → ꭰ ..ꮿ Cherokee */
|
||||
} else {
|
||||
l = 0;
|
||||
r = sizeof(kLower) / sizeof(kLower[0]);
|
||||
r = n = sizeof(kLower) / sizeof(kLower[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kLower[m].y < c) {
|
||||
|
@ -208,7 +208,7 @@ wint_t towlower(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
if (kLower[l].x <= c && c <= kLower[l].y) {
|
||||
if (l < n && kLower[l].x <= c && c <= kLower[l].y) {
|
||||
return c + kLower[l].d;
|
||||
} else {
|
||||
return c;
|
||||
|
@ -216,7 +216,7 @@ wint_t towlower(wint_t c) {
|
|||
}
|
||||
} else {
|
||||
l = 0;
|
||||
r = sizeof(kAstralLower) / sizeof(kAstralLower[0]);
|
||||
r = n = sizeof(kAstralLower) / sizeof(kAstralLower[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kAstralLower[m][1] < c) {
|
||||
|
@ -225,7 +225,7 @@ wint_t towlower(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
if (kAstralLower[l][0] <= c && c <= kAstralLower[l][1]) {
|
||||
if (l < n && kAstralLower[l][0] <= c && c <= kAstralLower[l][1]) {
|
||||
return c + kAstralLower[l][2];
|
||||
} else {
|
||||
return c;
|
||||
|
|
|
@ -140,7 +140,7 @@ static const int kAstralUpper[][3] = {
|
|||
* Converts wide character to upper case.
|
||||
*/
|
||||
wint_t towupper(wint_t c) {
|
||||
int m, l, r;
|
||||
int m, l, r, n;
|
||||
if (c < 0200) {
|
||||
if ('a' <= c && c <= 'z') {
|
||||
return c - 32;
|
||||
|
@ -162,7 +162,7 @@ wint_t towupper(wint_t c) {
|
|||
return c - 38864; /* 80x ꭰ ..ꮿ → Ꭰ ..Ꮿ Cherokee Supplement */
|
||||
} else {
|
||||
l = 0;
|
||||
r = sizeof(kUpper) / sizeof(kUpper[0]);
|
||||
r = n = sizeof(kUpper) / sizeof(kUpper[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kUpper[m].y < c) {
|
||||
|
@ -171,7 +171,7 @@ wint_t towupper(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
if (kUpper[l].x <= c && c <= kUpper[l].y) {
|
||||
if (l < n && kUpper[l].x <= c && c <= kUpper[l].y) {
|
||||
return c + kUpper[l].d;
|
||||
} else {
|
||||
return c;
|
||||
|
@ -179,7 +179,7 @@ wint_t towupper(wint_t c) {
|
|||
}
|
||||
} else {
|
||||
l = 0;
|
||||
r = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]);
|
||||
r = n = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]);
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (kAstralUpper[m][1] < c) {
|
||||
|
@ -188,7 +188,7 @@ wint_t towupper(wint_t c) {
|
|||
r = m;
|
||||
}
|
||||
}
|
||||
if (kAstralUpper[l][0] <= c && c <= kAstralUpper[l][1]) {
|
||||
if (l < n && kAstralUpper[l][0] <= c && c <= kAstralUpper[l][1]) {
|
||||
return c + kAstralUpper[l][2];
|
||||
} else {
|
||||
return c;
|
||||
|
|
|
@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
|
|||
testlib_runalltests();
|
||||
if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) {
|
||||
weaken(testlib_runallbenchmarks)();
|
||||
if (!g_testlib_failed) {
|
||||
if (!g_testlib_failed && IsRunningUnderMake()) {
|
||||
return 254; /* compile.com considers this 0 and propagates output */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -33,6 +34,27 @@
|
|||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
static uint64_t __zipos_get_min_offset(const uint8_t *base,
|
||||
const uint8_t *cdir) {
|
||||
uint64_t i, n, c, r, o;
|
||||
c = GetZipCdirOffset(cdir);
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (r = c, i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(base + c)) {
|
||||
o = GetZipCfileOffset(base + c);
|
||||
if (o < r) r = o;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __zipos_munmap_unneeded(const uint8_t *base, const uint8_t *cdir,
|
||||
const uint8_t *map) {
|
||||
uint64_t n;
|
||||
n = __zipos_get_min_offset(base, cdir);
|
||||
n += base - map;
|
||||
n = ROUNDDOWN(n, FRAMESIZE);
|
||||
if (n) munmap(map, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pointer to zip central directory of current executable.
|
||||
*/
|
||||
|
@ -40,30 +62,31 @@ struct Zipos *__zipos_get(void) {
|
|||
static bool once;
|
||||
static struct Zipos zipos;
|
||||
int fd;
|
||||
size_t n;
|
||||
char *path;
|
||||
size_t size;
|
||||
sigset_t neu, old;
|
||||
uint8_t *p, *base, *cdir;
|
||||
uint8_t *map, *base, *cdir;
|
||||
if (!once) {
|
||||
sigfillset(&neu);
|
||||
sigprocmask(SIG_BLOCK, &neu, &old);
|
||||
if ((fd = open(program_executable_name, O_RDONLY)) != -1) {
|
||||
if ((n = getfiledescriptorsize(fd)) != SIZE_MAX &&
|
||||
(p = mmap(0, n, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
|
||||
if ((size = getfiledescriptorsize(fd)) != SIZE_MAX &&
|
||||
(map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
|
||||
if (endswith(program_executable_name, ".com.dbg")) {
|
||||
if ((base = memmem(p, n, "MZqFpD", 6))) {
|
||||
n -= base - p;
|
||||
if ((base = memmem(map, size, "MZqFpD", 6))) {
|
||||
size -= base - map;
|
||||
} else {
|
||||
base = p;
|
||||
base = map;
|
||||
}
|
||||
} else {
|
||||
base = p;
|
||||
base = map;
|
||||
}
|
||||
if ((cdir = GetZipCdir(base, n))) {
|
||||
if ((cdir = GetZipCdir(base, size))) {
|
||||
__zipos_munmap_unneeded(base, cdir, map);
|
||||
zipos.map = base;
|
||||
zipos.cdir = cdir;
|
||||
} else {
|
||||
munmap(p, n);
|
||||
munmap(map, size);
|
||||
ZTRACE("__zipos_get(%s) → eocd not found", program_executable_name);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const signed char kHexToInt[256];
|
||||
extern const char kEscapeAuthority[256];
|
||||
extern const char kEscapeIp[256];
|
||||
extern const char kEscapePath[256];
|
||||
|
|
|
@ -337,6 +337,7 @@ TEST(strtoumax, testZero) {
|
|||
}
|
||||
TEST(strtoumax, testDecimal) {
|
||||
EXPECT_EQ(123, strtoumax("123", NULL, 0));
|
||||
EXPECT_EQ(-123, strtoumax("-123", NULL, 0));
|
||||
}
|
||||
TEST(strtoumax, testHex) {
|
||||
EXPECT_EQ(255, strtoumax("0xff", NULL, 0));
|
||||
|
|
|
@ -68,8 +68,8 @@ TEST(memmove, bighug) {
|
|||
int N[] = {5 * 1024 * 1024};
|
||||
a = gc(malloc(6291456));
|
||||
b = gc(malloc(6291456));
|
||||
for (o1 = 0; o1 < 40; o1 += 10) {
|
||||
for (o2 = 0; o2 < 40; o2 += 10) {
|
||||
for (o1 = 0; o1 < 40; o1 += 20) {
|
||||
for (o2 = 0; o2 < 40; o2 += 20) {
|
||||
for (i = 0; i < ARRAYLEN(N); ++i) {
|
||||
rngset(a, 6291456, 0, 0);
|
||||
memcpy(b, a, 6291456);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
|
@ -23,8 +25,9 @@
|
|||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
static void *golden(void *p, int c, size_t n) {
|
||||
static noasan void *golden(void *p, int c, size_t n) {
|
||||
size_t i;
|
||||
if (IsAsan()) __asan_check(p, n);
|
||||
for (i = 0; i < n; ++i) ((char *)p)[i] = c;
|
||||
return p;
|
||||
}
|
||||
|
@ -32,18 +35,16 @@ static void *golden(void *p, int c, size_t n) {
|
|||
TEST(memset, hug) {
|
||||
char *a, *b;
|
||||
int i, j, c;
|
||||
a = malloc(1025 * 2);
|
||||
b = malloc(1025 * 2);
|
||||
for (i = 0; i < 1025; ++i) {
|
||||
for (j = 0; j < 1025 - i; ++j) {
|
||||
a = malloc(i + j);
|
||||
b = malloc(i + j);
|
||||
c = vigna();
|
||||
rngset(a, i + j, vigna, 0);
|
||||
rngset(a, i + j, 0, 0);
|
||||
memcpy(b, a, i + j);
|
||||
ASSERT_EQ(a + i, golden(a + i, c, j));
|
||||
ASSERT_EQ(b + i, memset(b + i, c, j));
|
||||
ASSERT_EQ(0, timingsafe_bcmp(a, b, i + j));
|
||||
free(b);
|
||||
free(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,17 +52,15 @@ TEST(memset, hug) {
|
|||
TEST(bzero, hug) {
|
||||
char *a, *b;
|
||||
int i, j;
|
||||
a = malloc(1025 * 2);
|
||||
b = malloc(1025 * 2);
|
||||
for (i = 0; i < 1025; ++i) {
|
||||
for (j = 0; j < 1025 - i; ++j) {
|
||||
a = malloc(i + j);
|
||||
b = malloc(i + j);
|
||||
rngset(a, i + j, vigna, 0);
|
||||
rngset(a, i + j, 0, 0);
|
||||
memcpy(b, a, i + j);
|
||||
golden(a + i, 0, j);
|
||||
bzero(b + i, j);
|
||||
ASSERT_EQ(0, timingsafe_bcmp(a, b, i + j));
|
||||
free(b);
|
||||
free(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
65
test/libc/mem/arena_test.c
Normal file
65
test/libc/mem/arena_test.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/arena.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(arena, test) {
|
||||
EXPECT_STREQ("hello", gc(strdup("hello")));
|
||||
__arena_push();
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
__arena_push();
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
for (int i = 0; i < 5000; ++i) {
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
}
|
||||
free(strdup("hello"));
|
||||
__arena_pop();
|
||||
EXPECT_STREQ("", calloc(1, 16));
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
void *calloc_(size_t, size_t) asm("calloc");
|
||||
|
||||
void A(size_t n) {
|
||||
__arena_push();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
calloc_(15, 1);
|
||||
}
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
void B(size_t n) {
|
||||
void **P;
|
||||
P = malloc(n * sizeof(void *));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
P[i] = calloc_(15, 1);
|
||||
}
|
||||
bulk_free(P, n);
|
||||
free(P);
|
||||
}
|
||||
|
||||
BENCH(arena, bench) {
|
||||
EZBENCH2("A 100", donothing, A(100));
|
||||
EZBENCH2("B 100", donothing, B(100));
|
||||
EZBENCH2("A 5000", donothing, A(5000));
|
||||
EZBENCH2("B 5000", donothing, B(5000));
|
||||
}
|
|
@ -30,6 +30,7 @@
|
|||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define N 1024
|
||||
|
@ -82,3 +83,25 @@ TEST(malloc, test) {
|
|||
for (i = 0; i < ARRAYLEN(fds); ++i) close(fds[i]);
|
||||
malloc_trim(0);
|
||||
}
|
||||
|
||||
void *bulk[1024];
|
||||
|
||||
void BulkFreeBenchSetup(void) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(bulk); ++i) {
|
||||
bulk[i] = malloc(rand() % 64);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeBulk(void) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(bulk); ++i) {
|
||||
free(bulk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(bulk_free, bench) {
|
||||
EZBENCH2("free() bulk", BulkFreeBenchSetup(), FreeBulk());
|
||||
EZBENCH2("bulk_free()", BulkFreeBenchSetup(),
|
||||
bulk_free(bulk, ARRAYLEN(bulk)));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ TEST_LIBC_MEM_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TESTLIB
|
||||
LIBC_TESTLIB \
|
||||
THIRD_PARTY_DLMALLOC
|
||||
|
||||
TEST_LIBC_MEM_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_LIBC_MEM_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -17,11 +17,27 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
TEST(strsak32, test) {
|
||||
EXPECT_EQ(0, wcslen(L""));
|
||||
EXPECT_EQ(1, wcslen(L"1"));
|
||||
EXPECT_EQ(5, wcslen(L"hello"));
|
||||
}
|
||||
|
||||
BENCH(strsak32, bench) {
|
||||
size_t wcslen_(const wchar_t *) asm("wcslen");
|
||||
wchar_t *p = gc(utf8toutf32(kHyperion, kHyperionSize, 0));
|
||||
EZBENCH_N("wcslen", kHyperionSize, wcslen_(p));
|
||||
for (int i = 128; i >= 2; i /= 2) {
|
||||
p[i - 0] = 0;
|
||||
EZBENCH_N("wcslen", i - 0, wcslen_(p));
|
||||
p[i - 1] = 0;
|
||||
EZBENCH_N("wcslen", i - 1, wcslen_(p));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
|
|
@ -24,25 +24,6 @@
|
|||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
const signed char kHexToInt[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x20
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 0x30
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x40
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x50
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x60
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x70
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x80
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x90
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xa0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xb0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xc0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xd0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xe0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xf0
|
||||
};
|
||||
|
||||
uint8_t *EZBLAKE2B256(const char *s, size_t n) {
|
||||
static uint8_t digest[BLAKE2B256_DIGEST_LENGTH];
|
||||
BLAKE2B256(s, n, digest);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
|
@ -49,7 +50,38 @@ TEST(crc32c, test) {
|
|||
EXPECT_EQ(0xecc9871d, crc32c(0, kHyperion, kHyperionSize));
|
||||
}
|
||||
|
||||
BENCH(crc32c, bench) {
|
||||
EZBENCH2("crc32c", donothing, crc32c(0, kHyperion, kHyperionSize));
|
||||
EZBENCH2("crc32_z", donothing, crc32_z(0, kHyperion, kHyperionSize));
|
||||
noinline uint64_t fnv_hash(char *s, int len) {
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
for (int i = 0; i < len; i++) {
|
||||
hash *= 0x100000001b3;
|
||||
hash ^= (unsigned char)s[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static unsigned KMH(const void *p, unsigned long n) {
|
||||
unsigned h, i;
|
||||
for (h = i = 0; i < n; i++) {
|
||||
h += ((unsigned char *)p)[i];
|
||||
h *= 0x9e3779b1;
|
||||
}
|
||||
return MAX(1, h);
|
||||
}
|
||||
|
||||
BENCH(crc32c, bench) {
|
||||
for (int i = 1; i < 256; i *= 2) {
|
||||
EZBENCH_N("crc32c", i, crc32c(0, kHyperion, i));
|
||||
EZBENCH_N("crc32_z", i, crc32_z(0, kHyperion, i));
|
||||
EZBENCH_N("fnv_hash", i,
|
||||
EXPROPRIATE(fnv_hash(VEIL("r", kHyperion), VEIL("r", i))));
|
||||
EZBENCH_N("KMH", i, EXPROPRIATE(KMH(VEIL("r", kHyperion), VEIL("r", i))));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
EZBENCH_N("crc32c", kHyperionSize, crc32c(0, kHyperion, kHyperionSize));
|
||||
EZBENCH_N("crc32_z", kHyperionSize, crc32_z(0, kHyperion, kHyperionSize));
|
||||
EZBENCH_N(
|
||||
"fnv_hash", kHyperionSize,
|
||||
EXPROPRIATE(fnv_hash(VEIL("r", kHyperion), VEIL("r", kHyperionSize))));
|
||||
EZBENCH_N("KMH", kHyperionSize,
|
||||
EXPROPRIATE(KMH(VEIL("r", kHyperion), VEIL("r", kHyperionSize))));
|
||||
}
|
||||
|
|
51
test/libc/str/longsort_test.c
Normal file
51
test/libc/str/longsort_test.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
int CompareLong(const void *a, const void *b) {
|
||||
const long *x = a;
|
||||
const long *y = b;
|
||||
if (*x < *y) return -1;
|
||||
if (*x > *y) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(longsort, test) {
|
||||
size_t n = 5000;
|
||||
long *a = gc(calloc(n, sizeof(long)));
|
||||
long *b = gc(calloc(n, sizeof(long)));
|
||||
rngset(a, n * sizeof(long), 0, 0);
|
||||
memcpy(b, a, n * sizeof(long));
|
||||
qsort(a, n, sizeof(long), CompareLong);
|
||||
longsort(b, n);
|
||||
ASSERT_EQ(0, memcmp(b, a, n * sizeof(long)));
|
||||
}
|
||||
|
||||
BENCH(longsort, bench) {
|
||||
size_t n = 1000;
|
||||
long *p1 = gc(malloc(n * sizeof(long)));
|
||||
long *p2 = gc(malloc(n * sizeof(long)));
|
||||
rngset(p1, n * sizeof(long), 0, 0);
|
||||
EZBENCH2("longsort", memcpy(p2, p1, n * sizeof(long)), longsort(p2, n));
|
||||
}
|
|
@ -35,25 +35,6 @@ int CompareLong(const void *a, const void *b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned long doge(unsigned long x) {
|
||||
unsigned long t = 1;
|
||||
while (t < x - t) {
|
||||
t += t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
unsigned long B(unsigned long x) {
|
||||
return 1ul << bsrl(x - 1);
|
||||
}
|
||||
|
||||
TEST(eh, eu) {
|
||||
int i;
|
||||
for (i = 2; i < 9999; ++i) {
|
||||
ASSERT_EQ(doge(i), B(i), "%d", i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(qsort, test) {
|
||||
const int32_t A[][2] = {{4, 'a'}, {65, 'b'}, {2, 'c'}, {-31, 'd'},
|
||||
{0, 'e'}, {99, 'f'}, {2, 'g'}, {83, 'h'},
|
||||
|
@ -68,17 +49,6 @@ TEST(qsort, test) {
|
|||
free(M);
|
||||
}
|
||||
|
||||
TEST(longsort, test) {
|
||||
size_t n = 5000;
|
||||
long *a = gc(calloc(n, sizeof(long)));
|
||||
long *b = gc(calloc(n, sizeof(long)));
|
||||
rngset(a, n * sizeof(long), 0, 0);
|
||||
memcpy(b, a, n * sizeof(long));
|
||||
qsort(a, n, sizeof(long), CompareLong);
|
||||
longsort(b, n);
|
||||
ASSERT_EQ(0, memcmp(b, a, n * sizeof(long)));
|
||||
}
|
||||
|
||||
BENCH(qsort, bench) {
|
||||
size_t n = 1000;
|
||||
long *p1 = gc(malloc(n * sizeof(long)));
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/rand/rand.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(strchr, blank) {
|
||||
|
@ -84,8 +85,8 @@ TEST(strchr, fuzz) {
|
|||
p = calloc(1, 64);
|
||||
for (i = -2; i < 257; ++i) {
|
||||
for (j = 0; j < 17; ++j) {
|
||||
rngset(p, 63, rand64, -1);
|
||||
ASSERT_EQ(strchr(p + j, i), strchr_pure(p + j, i));
|
||||
rngset(p, 63, rdseed, -1);
|
||||
ASSERT_EQ(strchr_pure(p + j, i), strchr(p + j, i));
|
||||
}
|
||||
}
|
||||
free(p);
|
||||
|
@ -165,3 +166,20 @@ TEST(rawmemchr, fuzz) {
|
|||
}
|
||||
free(p);
|
||||
}
|
||||
|
||||
BENCH(strchr, bench2) {
|
||||
char *strchr_(const char *, int) asm("strchr");
|
||||
char *strchrnul_(const char *, int) asm("strchrnul");
|
||||
char *memchr_(const char *, int, size_t) asm("memchr");
|
||||
char *strlen_(const char *) asm("strlen");
|
||||
char *rawmemchr_(const char *, int) asm("rawmemchr");
|
||||
EZBENCH2("strchr z", donothing, strchr_(kHyperion, 'z'));
|
||||
EZBENCH2("rawmemchr z", donothing, rawmemchr_(kHyperion, 'z'));
|
||||
EZBENCH2("memchr z", donothing, memchr_(kHyperion, 'z', kHyperionSize));
|
||||
EZBENCH2("strchr Z", donothing, strchr_(kHyperion, 'Z'));
|
||||
EZBENCH2("rawmemchr \\0", donothing, rawmemchr_(kHyperion, 0));
|
||||
EZBENCH2("strlen", donothing, strlen_(kHyperion));
|
||||
EZBENCH2("memchr Z", donothing, memchr_(kHyperion, 'Z', kHyperionSize));
|
||||
EZBENCH2("strchrnul z", donothing, strchrnul_(kHyperion, 'z'));
|
||||
EZBENCH2("strchrnul Z", donothing, strchrnul_(kHyperion, 'Z'));
|
||||
}
|
||||
|
|
36
test/libc/str/strpbrk_test.c
Normal file
36
test/libc/str/strpbrk_test.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(strpbrk, test) {
|
||||
EXPECT_STREQ("o", strpbrk("hello", "abco"));
|
||||
EXPECT_EQ(NULL, strpbrk("hello", "ABCO"));
|
||||
}
|
||||
|
||||
BENCH(strpbrk, bench) {
|
||||
char *strchr_(const char *, int) asm("strchr");
|
||||
char *strpbrk_(const char *, const char *) asm("strpbrk");
|
||||
EZBENCH2("strchr", donothing, strchr_(kHyperion, 'z'));
|
||||
EZBENCH2("strpbrk 1", donothing, strpbrk_(kHyperion, "z"));
|
||||
EZBENCH2("strpbrk 2", donothing, strpbrk_(kHyperion, "Zz"));
|
||||
EZBENCH2("strpbrk 10", donothing, strpbrk_(kHyperion, ">@#\6\3\2\5\6Zz"));
|
||||
}
|
2
third_party/chibicc/README.cosmo
vendored
2
third_party/chibicc/README.cosmo
vendored
|
@ -6,6 +6,7 @@ which is great, considering it's a 220kb αcτµαlly pδrταblε εxεcµταb
|
|||
|
||||
local enhancements
|
||||
|
||||
- add assembler
|
||||
- support dce
|
||||
- support gnu asm
|
||||
- support __int128
|
||||
|
@ -24,6 +25,7 @@ local enhancements
|
|||
- reduce #lines of generated assembly by a third
|
||||
- reduce #bytes of generated binary by a third
|
||||
- report divide errors in constexprs
|
||||
- use perfect hash table for keywords
|
||||
|
||||
local bug fixes
|
||||
|
||||
|
|
238
third_party/chibicc/as.c
vendored
238
third_party/chibicc/as.c
vendored
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/def.h"
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -35,93 +37,6 @@
|
|||
#include "third_party/gdtoa/gdtoa.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Assembler
|
||||
*
|
||||
* This program turns assembly into relocatable NexGen32e ELF objects.
|
||||
* That process is normally an implementation detail of your compiler,
|
||||
* which can embed this program or launch it as a subprocess. Much GNU
|
||||
* style syntax is supported. Your code that gets embedded in an asm()
|
||||
* statement will ultimately end up here. This implementation, has the
|
||||
* advantage of behaving the same across platforms, in a simple single
|
||||
* file implementation that compiles down to a 100kilo ape executable.
|
||||
*
|
||||
* Your assembler supports the following flags:
|
||||
*
|
||||
* -o FILE output path [default: a.out]
|
||||
* -I DIR append include path [default: .]
|
||||
* -W inhibit .warning
|
||||
* -Z inhibit .error and .err
|
||||
*
|
||||
* Your assembler supports the following directives:
|
||||
*
|
||||
* .zero INT... emits int8
|
||||
* .word INT... emits int16
|
||||
* .long INT... emits int32
|
||||
* .quad INT... emits int64
|
||||
* .ascii STR... emits string
|
||||
* .asciz STR... emits string and 0 byte
|
||||
* .ident STR emits string to .comment section
|
||||
* .float NUMBER... emits binary32
|
||||
* .double NUMBER... emits binary64
|
||||
* .float80 NUMBER... emits x86 float (10 bytes)
|
||||
* .ldbl NUMBER... emits x86 float (16 bytes)
|
||||
* .sleb128 NUMBER... emits LEB-128 signed varint
|
||||
* .uleb128 NUMBER... emits LEB-128 unsigned varint
|
||||
* .align BYTES [FILL [MAXSKIP]] emits fill bytes to boundary
|
||||
* .end halts tokenization
|
||||
* .abort crashes assembler
|
||||
* .err aborts (ignorable w/ -Z)
|
||||
* .error STR aborts (ignorable w/ -Z)
|
||||
* .warning STR whines (ignorable w/ -W)
|
||||
* .text enters text section (default)
|
||||
* .data enters data section
|
||||
* .bss enters bss section
|
||||
* .section NAME [SFLG SHT] enters section
|
||||
* .previous enters previous section
|
||||
* .pushsection NAME [SFLG SHT] pushes section
|
||||
* .popsection pops section
|
||||
* .type SYM TYPE sets type of symbol
|
||||
* .size SYM EXPR sets size of symbol
|
||||
* .internal SYM... marks symbol STV_INTERNAL
|
||||
* .hidden SYM... marks symbol STV_HIDDEN
|
||||
* .protected SYM... marks symbol STV_PROTECTED
|
||||
* .globl SYM... marks symbol STB_GLOBAL
|
||||
* .local SYM... marks symbol STB_LOCAL
|
||||
* .weak SYM... marks symbol STB_WEAK
|
||||
* .include FILE assembles file source
|
||||
* .incbin FILE emits file content
|
||||
* .file FILENO PATH dwarf file define
|
||||
* .loc FILENO LINENO dwarf source line
|
||||
*
|
||||
* TYPE can be one of the following:
|
||||
*
|
||||
* - @notype STT_NOTYPE (default)
|
||||
* - @object STT_OBJECT
|
||||
* - @function STT_FUNC
|
||||
* - @common STT_COMMON
|
||||
* - @tls_object STT_TLS
|
||||
*
|
||||
* SHT can be one of the following:
|
||||
*
|
||||
* - @progbits SHT_PROGBITS
|
||||
* - @note SHT_NOTE
|
||||
* - @nobits SHT_NOBITS
|
||||
* - @preinit_array SHT_PREINIT_ARRAY
|
||||
* - @init_array SHT_INIT_ARRAY
|
||||
* - @fini_array SHT_FINI_ARRAY
|
||||
*
|
||||
* SFLG is a string which may have the following characters:
|
||||
*
|
||||
* - a SHF_ALLOC
|
||||
* - w SHF_WRITE
|
||||
* - x SHF_EXECINSTR
|
||||
* - g SHF_GROUP
|
||||
* - M SHF_MERGE
|
||||
* - S SHF_STRINGS
|
||||
* - T SHF_TLS
|
||||
*/
|
||||
|
||||
#define OSZ 0x66
|
||||
#define ASZ 0x67
|
||||
#define REX 0x40 // byte
|
||||
|
@ -144,7 +59,7 @@
|
|||
|
||||
#define IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define READ128BE(S) ((unsigned __int128)READ64BE(S) << 64 | READ64BE((S) + 8))
|
||||
#define READ128BE(S) ((uint128_t)READ64BE(S) << 64 | READ64BE((S) + 8))
|
||||
|
||||
struct As {
|
||||
int i; // things
|
||||
|
@ -158,7 +73,7 @@ struct As {
|
|||
bool inhibitwarn;
|
||||
struct Ints {
|
||||
unsigned long n, c;
|
||||
long *p;
|
||||
int128_t *p;
|
||||
} ints;
|
||||
struct Floats {
|
||||
unsigned long n, c;
|
||||
|
@ -276,7 +191,7 @@ struct As {
|
|||
unsigned tok;
|
||||
int lhs;
|
||||
int rhs;
|
||||
long x;
|
||||
int128_t x;
|
||||
bool isvisited;
|
||||
bool isevaluated;
|
||||
} * p;
|
||||
|
@ -431,14 +346,8 @@ static const struct Reg {
|
|||
{"xmm9", 1 | 4<<3 | REXR<<8, 1 | 4<<3 | REXB<<8, -1, -1 },
|
||||
} /* clang-format on */;
|
||||
|
||||
static unsigned Hash(const void *p, unsigned long n) {
|
||||
unsigned h, i;
|
||||
for (h = i = 0; i < n; i++) {
|
||||
h += ((unsigned char *)p)[i];
|
||||
h *= 0x9e3779b1;
|
||||
}
|
||||
return MAX(1, h);
|
||||
}
|
||||
long as_hashmap_hits;
|
||||
long as_hashmap_miss;
|
||||
|
||||
static bool IsPunctMergeable(int c) {
|
||||
switch (c) {
|
||||
|
@ -586,6 +495,7 @@ static void ReadFlags(struct As *a, int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
static int ReadCharLiteral(struct Slice *buf, int c, char *p, int *i) {
|
||||
int x;
|
||||
if (c != '\\') return c;
|
||||
switch ((c = p[(*i)++])) {
|
||||
case 'a':
|
||||
|
@ -605,10 +515,10 @@ static int ReadCharLiteral(struct Slice *buf, int c, char *p, int *i) {
|
|||
case 'e':
|
||||
return 033;
|
||||
case 'x':
|
||||
if (isxdigit(p[*i])) {
|
||||
c = hextoint(p[(*i)++]);
|
||||
if (isxdigit(p[*i])) {
|
||||
c = c * 16 + hextoint(p[(*i)++]);
|
||||
if ((x = kHexToInt[p[*i] & 255]) != -1) {
|
||||
*i += 1, c = x;
|
||||
if ((x = kHexToInt[p[*i] & 255]) != -1) {
|
||||
*i += 1, c = c << 4 | x;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
|
@ -670,6 +580,10 @@ static void Tokenize(struct As *a, int path) {
|
|||
char *p, *path2;
|
||||
struct Slice buf;
|
||||
bool bol, isfloat, isfpu;
|
||||
if (!fileexists(a->strings.p[path])) {
|
||||
fprintf(stderr, "%s: file not found\n", a->strings.p[path]);
|
||||
exit(1);
|
||||
}
|
||||
p = SaveString(&a->strings, read_file(a->strings.p[path]));
|
||||
p = skip_bom(p);
|
||||
canonicalize_newline(p);
|
||||
|
@ -779,7 +693,7 @@ static void Tokenize(struct As *a, int path) {
|
|||
a->things.p[a->things.n - 1].t = TT_FLOAT;
|
||||
} else {
|
||||
APPEND(a->ints);
|
||||
a->ints.p[a->ints.n - 1] = strtoul(p, NULL, 0);
|
||||
a->ints.p[a->ints.n - 1] = strtoumax(p, NULL, 0);
|
||||
a->things.p[a->things.n - 1].i = a->ints.n - 1;
|
||||
if (p[i] == 'f' || p[i] == 'F') {
|
||||
a->things.p[a->things.n - 1].t = TT_FORWARD;
|
||||
|
@ -859,22 +773,28 @@ static void Tokenize(struct As *a, int path) {
|
|||
static int GetSymbol(struct As *a, int name) {
|
||||
struct HashEntry *p;
|
||||
unsigned i, j, k, n, m, h, n2;
|
||||
h = Hash(a->slices.p[name].p, a->slices.p[name].n);
|
||||
if (!(h = crc32c(0, a->slices.p[name].p, a->slices.p[name].n))) h = 1;
|
||||
n = a->symbolindex.n;
|
||||
i = 0;
|
||||
if (n) {
|
||||
k = 0;
|
||||
do {
|
||||
for (;;) {
|
||||
i = (h + k + ((k + 1) >> 1)) & (n - 1);
|
||||
if (a->symbolindex.p[i].h == h &&
|
||||
a->slices.p[a->symbols.p[a->symbolindex.p[i].i].name].n ==
|
||||
a->slices.p[name].n &&
|
||||
!memcmp(a->slices.p[a->symbols.p[a->symbolindex.p[i].i].name].p,
|
||||
a->slices.p[name].p, a->slices.p[name].n)) {
|
||||
++as_hashmap_hits;
|
||||
return a->symbolindex.p[i].i;
|
||||
}
|
||||
if (!a->symbolindex.p[i].h) {
|
||||
break;
|
||||
} else {
|
||||
++k;
|
||||
} while (a->symbolindex.p[i].h);
|
||||
++as_hashmap_miss;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (++a->symbolindex.i >= (n >> 1)) {
|
||||
m = n ? n << 1 : 16;
|
||||
|
@ -983,7 +903,7 @@ static void ConsumeComma(struct As *a) {
|
|||
ConsumePunct(a, ',');
|
||||
}
|
||||
|
||||
static int NewPrimary(struct As *a, enum ExprKind k, long x) {
|
||||
static int NewPrimary(struct As *a, enum ExprKind k, int128_t x) {
|
||||
AppendExpr(a);
|
||||
a->exprs.p[a->exprs.n - 1].kind = k;
|
||||
a->exprs.p[a->exprs.n - 1].x = x;
|
||||
|
@ -1299,7 +1219,7 @@ static int Parse(struct As *a) {
|
|||
return ParseOr(a, &a->i, a->i);
|
||||
}
|
||||
|
||||
static long GetInt(struct As *a) {
|
||||
static int128_t GetInt(struct As *a) {
|
||||
int x;
|
||||
x = Parse(a);
|
||||
if (a->exprs.p[x].kind == EX_INT) {
|
||||
|
@ -1331,7 +1251,7 @@ static struct Slice GetSlice(struct As *a) {
|
|||
}
|
||||
}
|
||||
|
||||
static void EmitData(struct As *a, const void *p, unsigned long n) {
|
||||
static void EmitData(struct As *a, const void *p, uint128_t n) {
|
||||
struct Slice *s;
|
||||
s = &a->sections.p[a->section].binary;
|
||||
s->p = realloc(s->p, s->n + n);
|
||||
|
@ -1339,41 +1259,50 @@ static void EmitData(struct As *a, const void *p, unsigned long n) {
|
|||
s->n += n;
|
||||
}
|
||||
|
||||
static void EmitByte(struct As *a, unsigned long x) {
|
||||
static void EmitByte(struct As *a, uint128_t i) {
|
||||
uint8_t x = i;
|
||||
unsigned char b[1];
|
||||
b[0] = x >> 000;
|
||||
b[0] = (x & 0xff) >> 000;
|
||||
EmitData(a, b, 1);
|
||||
}
|
||||
|
||||
static void EmitWord(struct As *a, unsigned long x) {
|
||||
static void EmitWord(struct As *a, uint128_t i) {
|
||||
uint16_t x = i;
|
||||
unsigned char b[2];
|
||||
b[0] = x >> 000;
|
||||
b[1] = x >> 010;
|
||||
b[0] = (x & 0x00ff) >> 000;
|
||||
b[1] = (x & 0xff00) >> 010;
|
||||
EmitData(a, b, 2);
|
||||
}
|
||||
|
||||
static void EmitLong(struct As *a, unsigned long x) {
|
||||
static void EmitLong(struct As *a, uint128_t i) {
|
||||
uint32_t x = i;
|
||||
unsigned char b[4];
|
||||
b[0] = x >> 000;
|
||||
b[1] = x >> 010;
|
||||
b[2] = x >> 020;
|
||||
b[3] = x >> 030;
|
||||
b[0] = (x & 0x000000ff) >> 000;
|
||||
b[1] = (x & 0x0000ff00) >> 010;
|
||||
b[2] = (x & 0x00ff0000) >> 020;
|
||||
b[3] = (x & 0xff000000) >> 030;
|
||||
EmitData(a, b, 4);
|
||||
}
|
||||
|
||||
void EmitQuad(struct As *a, unsigned long x) {
|
||||
void EmitQuad(struct As *a, uint128_t i) {
|
||||
uint64_t x = i;
|
||||
unsigned char b[8];
|
||||
b[0] = x >> 000;
|
||||
b[1] = x >> 010;
|
||||
b[2] = x >> 020;
|
||||
b[3] = x >> 030;
|
||||
b[4] = x >> 040;
|
||||
b[5] = x >> 050;
|
||||
b[6] = x >> 060;
|
||||
b[7] = x >> 070;
|
||||
b[0] = (x & 0x00000000000000ff) >> 000;
|
||||
b[1] = (x & 0x000000000000ff00) >> 010;
|
||||
b[2] = (x & 0x0000000000ff0000) >> 020;
|
||||
b[3] = (x & 0x00000000ff000000) >> 030;
|
||||
b[4] = (x & 0x000000ff00000000) >> 040;
|
||||
b[5] = (x & 0x0000ff0000000000) >> 050;
|
||||
b[6] = (x & 0x00ff000000000000) >> 060;
|
||||
b[7] = (x & 0xff00000000000000) >> 070;
|
||||
EmitData(a, b, 8);
|
||||
}
|
||||
|
||||
void EmitOcta(struct As *a, uint128_t i) {
|
||||
EmitQuad(a, i);
|
||||
EmitQuad(a, i >> 64);
|
||||
}
|
||||
|
||||
static void EmitVarword(struct As *a, unsigned long x) {
|
||||
if (x > 255) EmitVarword(a, x >> 8);
|
||||
EmitByte(a, x);
|
||||
|
@ -1381,7 +1310,7 @@ static void EmitVarword(struct As *a, unsigned long x) {
|
|||
|
||||
static void OnSleb128(struct As *a, struct Slice s) {
|
||||
int c;
|
||||
long x;
|
||||
int128_t x;
|
||||
for (;;) {
|
||||
x = GetInt(a);
|
||||
for (;;) {
|
||||
|
@ -1401,7 +1330,7 @@ static void OnSleb128(struct As *a, struct Slice s) {
|
|||
|
||||
static void OnUleb128(struct As *a, struct Slice s) {
|
||||
int c;
|
||||
unsigned long x;
|
||||
uint128_t x;
|
||||
for (;;) {
|
||||
x = GetInt(a);
|
||||
do {
|
||||
|
@ -1415,6 +1344,23 @@ static void OnUleb128(struct As *a, struct Slice s) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OnZleb128(struct As *a, struct Slice s) {
|
||||
int c;
|
||||
uint128_t x;
|
||||
for (;;) {
|
||||
x = GetInt(a);
|
||||
x = (x << 1) ^ ((int128_t)x >> 127);
|
||||
do {
|
||||
c = x & 0x7f;
|
||||
x >>= 7;
|
||||
if (x) c |= 0x80;
|
||||
EmitByte(a, c);
|
||||
} while (x);
|
||||
if (IsSemicolon(a)) break;
|
||||
ConsumeComma(a);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnZero(struct As *a, struct Slice s) {
|
||||
long n;
|
||||
char *p;
|
||||
|
@ -1460,7 +1406,7 @@ static long GetRelaAddend(int kind) {
|
|||
}
|
||||
|
||||
static void EmitExpr(struct As *a, int expr, int kind,
|
||||
void emitter(struct As *, unsigned long)) {
|
||||
void emitter(struct As *, uint128_t)) {
|
||||
if (expr == -1) {
|
||||
emitter(a, 0);
|
||||
} else if (a->exprs.p[expr].kind == EX_INT) {
|
||||
|
@ -1477,7 +1423,7 @@ static void EmitExpr(struct As *a, int expr, int kind,
|
|||
}
|
||||
|
||||
static void OpInt(struct As *a, int kind,
|
||||
void emitter(struct As *, unsigned long)) {
|
||||
void emitter(struct As *, uint128_t)) {
|
||||
for (;;) {
|
||||
EmitExpr(a, Parse(a), kind, emitter);
|
||||
if (IsSemicolon(a)) break;
|
||||
|
@ -1501,6 +1447,10 @@ static void OnQuad(struct As *a, struct Slice s) {
|
|||
OpInt(a, R_X86_64_64, EmitQuad);
|
||||
}
|
||||
|
||||
static void OnOcta(struct As *a, struct Slice s) {
|
||||
OpInt(a, R_X86_64_64, EmitOcta);
|
||||
}
|
||||
|
||||
static void OnFloat(struct As *a, struct Slice s) {
|
||||
float f;
|
||||
char b[4];
|
||||
|
@ -1620,7 +1570,7 @@ static void OnPrevious(struct As *a, struct Slice s) {
|
|||
static void OnAlign(struct As *a, struct Slice s) {
|
||||
long i, n, align, fill, maxskip;
|
||||
align = GetInt(a);
|
||||
if (__builtin_popcountl(align) != 1) Fail(a, "alignment not power of 2");
|
||||
if (!IS2POW(align)) Fail(a, "alignment not power of 2");
|
||||
fill = (a->sections.p[a->section].flags & SHF_EXECINSTR) ? 0x90 : 0;
|
||||
maxskip = 268435456;
|
||||
if (IsComma(a)) {
|
||||
|
@ -1910,7 +1860,7 @@ static unsigned long MakeKey64(const char *p, int n) {
|
|||
return READ64BE(k);
|
||||
}
|
||||
|
||||
static unsigned __int128 MakeKey128(const char *p, int n) {
|
||||
static uint128_t MakeKey128(const char *p, int n) {
|
||||
char k[16] = {0};
|
||||
CopyLower(k, p, n);
|
||||
return READ128BE(k);
|
||||
|
@ -2088,7 +2038,7 @@ static void EmitImm(struct As *a, int reg, int imm) {
|
|||
|
||||
static void EmitModrm(struct As *a, int reg, int modrm, int disp) {
|
||||
int relo, mod, rm;
|
||||
void (*emitter)(struct As *, unsigned long);
|
||||
void (*emitter)(struct As *, uint128_t);
|
||||
reg &= 7;
|
||||
reg <<= 3;
|
||||
if (modrm & ISREG) {
|
||||
|
@ -2717,12 +2667,14 @@ static noinline void OpJmpImpl(struct As *a, int cc) {
|
|||
if (IsPunct(a, a->i, '*')) ++a->i;
|
||||
modrm = RemoveRexw(ParseModrm(a, &disp));
|
||||
if (cc == -1) {
|
||||
if ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) {
|
||||
modrm |= ISRIP;
|
||||
a->pcrelative = R_X86_64_GOTPCRELX;
|
||||
}
|
||||
if (modrm & (ISREG | ISRIP | HASINDEX | HASBASE)) {
|
||||
if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX;
|
||||
EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0);
|
||||
a->pcrelative = 0;
|
||||
} else {
|
||||
EmitByte(a, 0xE9);
|
||||
EmitExpr(a, disp, R_X86_64_PC32, EmitLong);
|
||||
}
|
||||
} else {
|
||||
EmitByte(a, 0x0F);
|
||||
EmitByte(a, 0x80 + cc);
|
||||
|
@ -3141,6 +3093,7 @@ static const struct Directive8 {
|
|||
{".loc", OnLoc}, //
|
||||
{".local", OnLocal}, //
|
||||
{".long", OnLong}, //
|
||||
{".octa", OnOcta}, //
|
||||
{".quad", OnQuad}, //
|
||||
{".section", OnSection}, //
|
||||
{".short", OnWord}, //
|
||||
|
@ -3154,6 +3107,7 @@ static const struct Directive8 {
|
|||
{".weak", OnWeak}, //
|
||||
{".word", OnWord}, //
|
||||
{".zero", OnZero}, //
|
||||
{".zleb128", OnZleb128}, //
|
||||
{"adc", OnAdc}, //
|
||||
{"adcb", OnAdc}, //
|
||||
{"adcl", OnAdc}, //
|
||||
|
@ -4024,7 +3978,7 @@ static void PrintThings(struct As *a) {
|
|||
a->sauces.p[a->things.p[i].s].line);
|
||||
switch (a->things.p[i].t) {
|
||||
case TT_INT:
|
||||
printf("TT_INT %ld\n", a->ints.p[a->things.p[i].i]);
|
||||
printf("TT_INT %jd\n", a->ints.p[a->things.p[i].i]);
|
||||
break;
|
||||
case TT_FLOAT:
|
||||
g_xfmt_p(fbuf, &a->floats.p[a->things.p[i].i], 19, sizeof(fbuf), 0);
|
||||
|
@ -4038,10 +3992,10 @@ static void PrintThings(struct As *a) {
|
|||
printf("TT_PUNCT %s\n", PunctToStr(a->things.p[i].i, pbuf));
|
||||
break;
|
||||
case TT_BACKWARD:
|
||||
printf("TT_BACKWARD %d\n", a->ints.p[a->things.p[i].i]);
|
||||
printf("TT_BACKWARD %jd\n", a->ints.p[a->things.p[i].i]);
|
||||
break;
|
||||
case TT_FORWARD:
|
||||
printf("TT_FORWARD %d\n", a->ints.p[a->things.p[i].i]);
|
||||
printf("TT_FORWARD %jd\n", a->ints.p[a->things.p[i].i]);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
|
|
1
third_party/chibicc/asm.c
vendored
1
third_party/chibicc/asm.c
vendored
|
@ -68,6 +68,7 @@ static void DecodeAsmConstraints(AsmOperand *op) {
|
|||
case 'J': // i∊[0,63] 6 bits for 64-bit shifts
|
||||
case 'N': // i∊[0,255] in/out immediate byte
|
||||
case 'K': // i∊[-128,127] signed byte integer
|
||||
case 'e': // i∊[-2^31,2^31) for sign-extending
|
||||
case 'Z': // i∊[0,2³²) for zero-extending
|
||||
case 'L': // i∊{0xFF,0xFFFF,0xFFFFFFFF}
|
||||
op->type |= kAsmImm;
|
||||
|
|
128
third_party/chibicc/chibicc.c
vendored
128
third_party/chibicc/chibicc.c
vendored
|
@ -1,5 +1,8 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
|
@ -36,6 +39,7 @@ bool opt_verbose;
|
|||
static bool opt_A;
|
||||
static bool opt_E;
|
||||
static bool opt_J;
|
||||
static bool opt_P;
|
||||
static bool opt_M;
|
||||
static bool opt_MD;
|
||||
static bool opt_MMD;
|
||||
|
@ -60,10 +64,13 @@ static StringArray std_include_paths;
|
|||
char *base_file;
|
||||
static char *output_file;
|
||||
static StringArray input_paths;
|
||||
static char **tmpfiles;
|
||||
char **chibicc_tmpfiles;
|
||||
|
||||
static void usage(int status) {
|
||||
fprintf(stderr, "chibicc [ -o <path> ] <file>\n");
|
||||
char *p;
|
||||
size_t n;
|
||||
p = gc(xslurp("/zip/third_party/chibicc/help.txt", &n));
|
||||
xwrite(1, p, n);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
@ -94,6 +101,7 @@ static void add_default_include_paths(char *argv0) {
|
|||
/* strarray_push(&include_paths, buf); */
|
||||
// Add standard include paths.
|
||||
/* strarray_push(&include_paths, "."); */
|
||||
strarray_push(&include_paths, "/zip/.c");
|
||||
// Keep a copy of the standard include paths for -MMD option.
|
||||
for (int i = 0; i < include_paths.len; i++) {
|
||||
strarray_push(&std_include_paths, include_paths.data[i]);
|
||||
|
@ -157,6 +165,10 @@ static void PrintMemoryUsage(void) {
|
|||
sizeof(Obj) * alloc_obj_count);
|
||||
fprintf(stderr, "allocated %,ld types (%,ld bytes)\n", alloc_type_count,
|
||||
sizeof(Type) * alloc_type_count);
|
||||
fprintf(stderr, "chibicc hashmap hits %,ld\n", chibicc_hashmap_hits);
|
||||
fprintf(stderr, "chibicc hashmap miss %,ld\n", chibicc_hashmap_miss);
|
||||
fprintf(stderr, "as hashmap hits %,ld\n", as_hashmap_hits);
|
||||
fprintf(stderr, "as hashmap miss %,ld\n", as_hashmap_miss);
|
||||
}
|
||||
|
||||
static void strarray_push_comma(StringArray *a, char *s) {
|
||||
|
@ -177,10 +189,10 @@ static void parse_args(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
}
|
||||
StringArray idirafter = {};
|
||||
StringArray idirafter = {0};
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-###")) {
|
||||
opt_hash_hash_hash = true;
|
||||
opt_verbose = opt_hash_hash_hash = true;
|
||||
} else if (!strcmp(argv[i], "-cc1")) {
|
||||
opt_cc1 = true;
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
|
@ -202,6 +214,8 @@ static void parse_args(int argc, char **argv) {
|
|||
opt_common = false;
|
||||
} else if (!strcmp(argv[i], "-fno-builtin")) {
|
||||
opt_no_builtin = true;
|
||||
} else if (!strcmp(argv[i], "-save-temps")) {
|
||||
opt_save_temps = true;
|
||||
} else if (!strcmp(argv[i], "-c")) {
|
||||
opt_c = true;
|
||||
} else if (!strcmp(argv[i], "-E")) {
|
||||
|
@ -210,6 +224,8 @@ static void parse_args(int argc, char **argv) {
|
|||
opt_J = true;
|
||||
} else if (!strcmp(argv[i], "-A")) {
|
||||
opt_A = true;
|
||||
} else if (!strcmp(argv[i], "-P")) {
|
||||
opt_P = true;
|
||||
} else if (!strcmp(argv[i], "-I")) {
|
||||
strarray_push(&include_paths, argv[++i]);
|
||||
} else if (startswith(argv[i], "-I")) {
|
||||
|
@ -350,9 +366,10 @@ static char *replace_extn(char *tmpl, char *extn) {
|
|||
}
|
||||
|
||||
static void cleanup(void) {
|
||||
if (tmpfiles && !opt_save_temps) {
|
||||
for (int i = 0; tmpfiles[i]; i++) {
|
||||
unlink(tmpfiles[i]);
|
||||
size_t i;
|
||||
if (chibicc_tmpfiles && !opt_save_temps) {
|
||||
for (i = 0; chibicc_tmpfiles[i]; i++) {
|
||||
unlink(chibicc_tmpfiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -363,9 +380,9 @@ static char *create_tmpfile(void) {
|
|||
if (fd == -1) error("mkstemp failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
static int len = 2;
|
||||
tmpfiles = realloc(tmpfiles, sizeof(char *) * len);
|
||||
tmpfiles[len - 2] = path;
|
||||
tmpfiles[len - 1] = NULL;
|
||||
chibicc_tmpfiles = realloc(chibicc_tmpfiles, sizeof(char *) * len);
|
||||
chibicc_tmpfiles[len - 2] = path;
|
||||
chibicc_tmpfiles[len - 1] = NULL;
|
||||
len++;
|
||||
return path;
|
||||
}
|
||||
|
@ -377,12 +394,50 @@ static void handle_exit(bool ok) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool NeedsShellQuotes(const char *s) {
|
||||
if (*s) {
|
||||
for (;;) {
|
||||
switch (*s++ & 255) {
|
||||
case 0:
|
||||
return false;
|
||||
case '-':
|
||||
case '.':
|
||||
case '/':
|
||||
case '_':
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool run_subprocess(char **argv) {
|
||||
// If -### is given, dump the subprocess's command line.
|
||||
if (opt_hash_hash_hash) {
|
||||
fprintf(stderr, "%s", argv[0]);
|
||||
for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
int rc, ws;
|
||||
size_t i, j, n;
|
||||
if (opt_verbose) {
|
||||
for (i = 0; argv[i]; i++) {
|
||||
fputc(' ', stderr);
|
||||
if (opt_hash_hash_hash && NeedsShellQuotes(argv[i])) {
|
||||
fputc('\'', stderr);
|
||||
for (j = 0; argv[i][j]; ++j) {
|
||||
if (argv[i][j] != '\'') {
|
||||
fputc(argv[i][j], stderr);
|
||||
} else {
|
||||
fputs("'\"'\"'", stderr);
|
||||
}
|
||||
}
|
||||
fputc('\'', stderr);
|
||||
} else {
|
||||
fputs(argv[i], stderr);
|
||||
}
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
if (!vfork()) {
|
||||
// Child process. Run a new command.
|
||||
|
@ -390,13 +445,9 @@ static bool run_subprocess(char **argv) {
|
|||
_exit(1);
|
||||
}
|
||||
// Wait for the child process to finish.
|
||||
int status;
|
||||
for (;;) {
|
||||
if (wait(&status) <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !status;
|
||||
do rc = wait(&ws);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
return WIFEXITED(ws) && WEXITSTATUS(ws) == 0;
|
||||
}
|
||||
|
||||
static bool run_cc1(int argc, char **argv, char *input, char *output) {
|
||||
|
@ -480,7 +531,7 @@ static void print_dependencies(void) {
|
|||
File **files = get_input_files();
|
||||
for (int i = 0; files[i]; i++) {
|
||||
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
|
||||
fprintf(out, " \\\n %s", files[i]->name);
|
||||
fprintf(out, " \\\n\t%s", files[i]->name);
|
||||
}
|
||||
fprintf(out, "\n\n");
|
||||
if (opt_MP) {
|
||||
|
@ -559,6 +610,10 @@ static void cc1(void) {
|
|||
output_javadown(output_file, prog);
|
||||
return;
|
||||
}
|
||||
if (opt_P) {
|
||||
output_bindings_python(output_file, prog, tok2);
|
||||
return;
|
||||
}
|
||||
FILE *out = open_file(output_file);
|
||||
codegen(prog, out);
|
||||
fclose(out);
|
||||
|
@ -573,7 +628,7 @@ static int CountArgv(char **argv) {
|
|||
static void assemble(char *input, char *output) {
|
||||
char *as = getenv("AS");
|
||||
if (!as || !*as) as = "as";
|
||||
StringArray arr = {};
|
||||
StringArray arr = {0};
|
||||
strarray_push(&arr, as);
|
||||
strarray_push(&arr, "-W");
|
||||
strarray_push(&arr, "-I.");
|
||||
|
@ -584,9 +639,11 @@ static void assemble(char *input, char *output) {
|
|||
strarray_push(&arr, input);
|
||||
strarray_push(&arr, "-o");
|
||||
strarray_push(&arr, output);
|
||||
strarray_push(&arr, NULL);
|
||||
if (1) {
|
||||
bool kludge = opt_save_temps;
|
||||
opt_save_temps = true;
|
||||
Assembler(CountArgv(arr.data), arr.data);
|
||||
opt_save_temps = kludge;
|
||||
} else {
|
||||
handle_exit(run_subprocess(arr.data));
|
||||
}
|
||||
|
@ -595,7 +652,7 @@ static void assemble(char *input, char *output) {
|
|||
static void run_linker(StringArray *inputs, char *output) {
|
||||
char *ld = getenv("LD");
|
||||
if (!ld || !*ld) ld = "ld";
|
||||
StringArray arr = {};
|
||||
StringArray arr = {0};
|
||||
strarray_push(&arr, ld);
|
||||
strarray_push(&arr, "-o");
|
||||
strarray_push(&arr, output);
|
||||
|
@ -618,7 +675,6 @@ static void run_linker(StringArray *inputs, char *output) {
|
|||
for (int i = 0; i < inputs->len; i++) {
|
||||
strarray_push(&arr, inputs->data[i]);
|
||||
}
|
||||
strarray_push(&arr, NULL);
|
||||
handle_exit(run_subprocess(arr.data));
|
||||
}
|
||||
|
||||
|
@ -630,9 +686,16 @@ int chibicc(int argc, char **argv) {
|
|||
showcrashreports();
|
||||
sigaction(SIGINT, &(struct sigaction){.sa_sigaction = OnCtrlC}, NULL);
|
||||
atexit(cleanup);
|
||||
init_macros();
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-cc1")) {
|
||||
opt_cc1 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (opt_cc1) init_macros();
|
||||
parse_args(argc, argv);
|
||||
if (opt_cc1) {
|
||||
init_macros_conditional();
|
||||
add_default_include_paths(argv[0]);
|
||||
cc1();
|
||||
return 0;
|
||||
|
@ -640,8 +703,8 @@ int chibicc(int argc, char **argv) {
|
|||
if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E)) {
|
||||
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
|
||||
}
|
||||
StringArray ld_args = {};
|
||||
StringArray dox_args = {};
|
||||
StringArray ld_args = {0};
|
||||
StringArray dox_args = {0};
|
||||
for (int i = 0; i < input_paths.len; i++) {
|
||||
char *input = input_paths.data[i];
|
||||
if (!strncmp(input, "-l", 2)) {
|
||||
|
@ -701,6 +764,11 @@ int chibicc(int argc, char **argv) {
|
|||
handle_exit(run_cc1(argc, argv, input, NULL));
|
||||
continue;
|
||||
}
|
||||
// Python Bindings
|
||||
if (opt_P) {
|
||||
handle_exit(run_cc1(argc, argv, input, opt_o ? opt_o : "/dev/stdout"));
|
||||
continue;
|
||||
}
|
||||
// Compile
|
||||
if (opt_S) {
|
||||
handle_exit(run_cc1(argc, argv, input, output));
|
||||
|
|
19
third_party/chibicc/chibicc.h
vendored
19
third_party/chibicc/chibicc.h
vendored
|
@ -96,6 +96,7 @@ struct thatispacked Token {
|
|||
int line_no; // Line number
|
||||
int line_delta; // Line number
|
||||
TokenKind kind; // Token kind
|
||||
uint8_t kw; // Keyword Phash
|
||||
bool at_bol; // True if this token is at beginning of line
|
||||
bool has_space; // True if this token follows a space character
|
||||
char *loc; // Token location
|
||||
|
@ -159,6 +160,7 @@ extern HashMap macros;
|
|||
|
||||
char *search_include_paths(char *);
|
||||
void init_macros(void);
|
||||
void init_macros_conditional(void);
|
||||
void define_macro(char *, char *);
|
||||
void undef_macro(char *);
|
||||
Token *preprocess(Token *);
|
||||
|
@ -448,7 +450,10 @@ struct Type {
|
|||
bool is_unsigned; // unsigned or signed
|
||||
bool is_atomic; // true if _Atomic
|
||||
bool is_const; // const
|
||||
bool is_restrict; // restrict
|
||||
bool is_volatile; // volatile
|
||||
bool is_ms_abi; // microsoft abi
|
||||
bool is_static; // for array parameter pointer
|
||||
Type *origin; // for type compatibility check
|
||||
// Pointer-to or array-of type. We intentionally use the same member
|
||||
// to represent pointer/array duality in C.
|
||||
|
@ -462,7 +467,7 @@ struct Type {
|
|||
// Declaration
|
||||
Token *name;
|
||||
Token *name_pos;
|
||||
// Array
|
||||
// Array or decayed pointer
|
||||
int array_len;
|
||||
int vector_size;
|
||||
// Variable-length array
|
||||
|
@ -570,6 +575,9 @@ struct HashMap {
|
|||
int used;
|
||||
};
|
||||
|
||||
extern long chibicc_hashmap_hits;
|
||||
extern long chibicc_hashmap_miss;
|
||||
|
||||
void *hashmap_get(HashMap *, char *);
|
||||
void *hashmap_get2(HashMap *, char *, int);
|
||||
void hashmap_put(HashMap *, char *, void *);
|
||||
|
@ -597,6 +605,7 @@ extern bool opt_sse3;
|
|||
extern bool opt_sse4;
|
||||
extern bool opt_verbose;
|
||||
extern char *base_file;
|
||||
extern char **chibicc_tmpfiles;
|
||||
|
||||
int chibicc(int, char **);
|
||||
|
||||
|
@ -631,8 +640,16 @@ void drop_dox(const StringArray *, const char *);
|
|||
// as.c
|
||||
//
|
||||
|
||||
extern long as_hashmap_hits;
|
||||
extern long as_hashmap_miss;
|
||||
|
||||
void Assembler(int, char **);
|
||||
|
||||
//
|
||||
// pybind.c
|
||||
//
|
||||
void output_bindings_python(const char *, Obj *, Token *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */
|
||||
|
|
4
third_party/chibicc/chibicc.mk
vendored
4
third_party/chibicc/chibicc.mk
vendored
|
@ -25,6 +25,7 @@ THIRD_PARTY_CHIBICC2_A = o/$(MODE)/third_party/chibicc/chibicc2.a
|
|||
THIRD_PARTY_CHIBICC_A_FILES := $(wildcard third_party/chibicc/*)
|
||||
THIRD_PARTY_CHIBICC_A_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
THIRD_PARTY_CHIBICC_A_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
THIRD_PARTY_CHIBICC_A_INCS = $(filter %.inc,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
|
||||
THIRD_PARTY_CHIBICC_DEFINES = \
|
||||
-DCRT=\"$(CRT)\" \
|
||||
|
@ -94,6 +95,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
|
|||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
$(APE) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.main.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
@$(APELINK)
|
||||
|
@ -102,6 +104,7 @@ o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
|
|||
$(THIRD_PARTY_CHIBICC2_A) \
|
||||
$(APE) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.main.chibicc.o \
|
||||
$(THIRD_PARTY_CHIBICC2_A).pkg
|
||||
@$(APELINK)
|
||||
|
@ -129,6 +132,7 @@ o/$(MODE)/%.chibicc2.o: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
|
|||
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_HDRS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_HDRS))
|
||||
THIRD_PARTY_CHIBICC_INCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_INCS))
|
||||
THIRD_PARTY_CHIBICC_CHECKS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_CHECKS))
|
||||
THIRD_PARTY_CHIBICC_OBJS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_OBJS))
|
||||
$(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk
|
||||
|
|
45
third_party/chibicc/codegen.c
vendored
45
third_party/chibicc/codegen.c
vendored
|
@ -22,32 +22,31 @@ void flushln(void) {
|
|||
}
|
||||
|
||||
static void processln(char *nextline) {
|
||||
#define LASTEQUAL(S) (lastlen == strlen(S) && !memcmp(lastline, S, lastlen))
|
||||
size_t lastlen;
|
||||
if (lastline) {
|
||||
lastlen = strlen(lastline);
|
||||
// unsophisticated optimization pass to reduce asm noise a little bit
|
||||
if ((!strcmp(lastline, "\txor\t%eax,%eax") &&
|
||||
!strcmp(nextline, "\tcltq")) ||
|
||||
(!strcmp(lastline, "\tmov\t$0x1,%eax") &&
|
||||
!strcmp(nextline, "\tcltq")) ||
|
||||
(!strcmp(lastline, "\tmovslq\t(%rax),%rax") &&
|
||||
!strcmp(nextline, "\tcltq"))) {
|
||||
if ((LASTEQUAL("\txor\t%eax,%eax") && !strcmp(nextline, "\tcltq")) ||
|
||||
(LASTEQUAL("\tmov\t$0x1,%eax") && !strcmp(nextline, "\tcltq")) ||
|
||||
(LASTEQUAL("\tmovslq\t(%rax),%rax") && !strcmp(nextline, "\tcltq"))) {
|
||||
free(nextline);
|
||||
} else if (!strcmp(lastline, "\tmov\t(%rax),%rax") &&
|
||||
} else if (LASTEQUAL("\tmov\t(%rax),%rax") &&
|
||||
!strcmp(nextline, "\tpush\t%rax")) {
|
||||
free(lastline);
|
||||
free(nextline);
|
||||
lastline = strdup("\tpush\t(%rax)");
|
||||
} else if (!strcmp(lastline, "\tmov\t$0x1,%eax") &&
|
||||
} else if (LASTEQUAL("\tmov\t$0x1,%eax") &&
|
||||
!strcmp(nextline, "\tpush\t%rax")) {
|
||||
free(lastline);
|
||||
free(nextline);
|
||||
lastline = strdup("\tpush\t$1");
|
||||
} else if (!strcmp(lastline, "\tpush\t(%rax)") &&
|
||||
} else if (LASTEQUAL("\tpush\t(%rax)") &&
|
||||
!strcmp(nextline, "\tpop\t%rdi")) {
|
||||
free(lastline);
|
||||
free(nextline);
|
||||
lastline = strdup("\tmov\t(%rax),%rdi");
|
||||
} else if (!strcmp(lastline, "\tpush\t%rax") &&
|
||||
!strcmp(nextline, "\tpop\t%rdi")) {
|
||||
} else if (LASTEQUAL("\tpush\t%rax") && !strcmp(nextline, "\tpop\t%rdi")) {
|
||||
free(lastline);
|
||||
free(nextline);
|
||||
lastline = strdup("\tmov\t%rax,%rdi");
|
||||
|
@ -58,6 +57,7 @@ static void processln(char *nextline) {
|
|||
} else {
|
||||
lastline = nextline;
|
||||
}
|
||||
#undef LASTEQUAL
|
||||
}
|
||||
|
||||
static void emitlin(char *nextline) {
|
||||
|
@ -184,6 +184,8 @@ static void print_align(int align) {
|
|||
}
|
||||
|
||||
void print_loc(int64_t file, int64_t line) {
|
||||
// TODO: This is broken if file is different? See gperf codegen.
|
||||
return;
|
||||
static int64_t lastfile = -1;
|
||||
static int64_t lastline = -1;
|
||||
char *locbuf, *p;
|
||||
|
@ -194,6 +196,7 @@ void print_loc(int64_t file, int64_t line) {
|
|||
*p++ = ' ';
|
||||
int64toarray_radix10(line, p);
|
||||
emitlin(locbuf);
|
||||
free(locbuf);
|
||||
lastfile = file;
|
||||
lastline = line;
|
||||
}
|
||||
|
@ -259,6 +262,14 @@ static char *reg_ax(int sz) {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static const char *gotpcrel(void) {
|
||||
if (opt_pic) {
|
||||
return "@gotpcrel(%rip)";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the absolute address of a given node.
|
||||
// It's an error if a given node does not reside in memory.
|
||||
// asm() wants this to not clobber flags or regs other than rax.
|
||||
|
@ -1502,11 +1513,10 @@ void gen_expr(Node *node) {
|
|||
load(node->cas_old->ty->base);
|
||||
pop("%rdx"); // new
|
||||
pop("%rdi"); // addr
|
||||
int sz = node->cas_addr->ty->base->size;
|
||||
println("\tlock cmpxchg %s,(%%rdi)", reg_dx(sz));
|
||||
println("\tlock cmpxchg %s,(%%rdi)", reg_dx(node->ty->size));
|
||||
emitlin("\tsete\t%cl");
|
||||
emitlin("\tje\t1f");
|
||||
println("\tmov\t%s,(%%r8)", reg_ax(sz));
|
||||
println("\tmov\t%s,(%%r8)", reg_ax(node->ty->size));
|
||||
emitlin("1:");
|
||||
emitlin("\tmovzbl\t%cl,%eax");
|
||||
return;
|
||||
|
@ -1516,8 +1526,7 @@ void gen_expr(Node *node) {
|
|||
push();
|
||||
gen_expr(node->rhs);
|
||||
pop("%rdi");
|
||||
int sz = node->lhs->ty->base->size;
|
||||
println("\txchg\t%s,(%%rdi)", reg_ax(sz));
|
||||
println("\txchg\t%s,(%%rdi)", reg_ax(node->ty->size));
|
||||
return;
|
||||
}
|
||||
case ND_FPCLASSIFY:
|
||||
|
@ -2314,9 +2323,9 @@ static void emit_function_hook(void) {
|
|||
if (opt_nop_mcount) {
|
||||
print_profiling_nop();
|
||||
} else if (opt_fentry) {
|
||||
emitlin("\tcall\t__fentry__@gotpcrel(%rip)");
|
||||
println("\tcall\t__fentry__%s", gotpcrel());
|
||||
} else if (opt_pg) {
|
||||
emitlin("\tcall\tmcount@gotpcrel(%rip)");
|
||||
println("\tcall\tmcount%s", gotpcrel());
|
||||
} else {
|
||||
print_profiling_nop();
|
||||
}
|
||||
|
|
91
third_party/chibicc/file.c
vendored
91
third_party/chibicc/file.c
vendored
|
@ -45,19 +45,51 @@ char *skip_bom(char *p) {
|
|||
|
||||
// Replaces \r or \r\n with \n.
|
||||
void canonicalize_newline(char *p) {
|
||||
int i = 0, j = 0;
|
||||
while (p[i]) {
|
||||
if (p[i] == '\r' && p[i + 1] == '\n') {
|
||||
i += 2;
|
||||
p[j++] = '\n';
|
||||
} else if (p[i] == '\r') {
|
||||
i++;
|
||||
p[j++] = '\n';
|
||||
char *q = p;
|
||||
for (;;) {
|
||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__chibicc__) // :'(
|
||||
typedef char xmm_u __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
if (!((uintptr_t)p & 15)) {
|
||||
xmm_t v;
|
||||
unsigned m;
|
||||
xmm_t z = {0};
|
||||
xmm_t s = {'\r', '\r', '\r', '\r', '\r', '\r', '\r', '\r',
|
||||
'\r', '\r', '\r', '\r', '\r', '\r', '\r', '\r'};
|
||||
xmm_t t = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
|
||||
'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
|
||||
for (;;) {
|
||||
v = *(const xmm_t *)p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == s) | (v == t));
|
||||
if (!m) {
|
||||
*(xmm_u *)q = v;
|
||||
p += 16;
|
||||
q += 16;
|
||||
} else {
|
||||
p[j++] = p[i++];
|
||||
m = bsf(m);
|
||||
memmove(q, p, m);
|
||||
p += m;
|
||||
q += m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p[j] = '\0';
|
||||
}
|
||||
#endif
|
||||
if (p[0]) {
|
||||
if (p[0] == '\r' && p[1] == '\n') {
|
||||
p += 2;
|
||||
*q++ = '\n';
|
||||
} else if (p[0] == '\r') {
|
||||
p += 1;
|
||||
*q++ = '\n';
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
// Removes backslashes followed by a newline.
|
||||
|
@ -68,7 +100,41 @@ void remove_backslash_newline(char *p) {
|
|||
// This counter maintain the number of newlines we have removed.
|
||||
int n = 0;
|
||||
bool instring = false;
|
||||
while (p[i]) {
|
||||
for (;;) {
|
||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__chibicc__) // :'(
|
||||
typedef char xmm_u __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
if (!((uintptr_t)(p + i) & 15)) {
|
||||
xmm_t v;
|
||||
unsigned m;
|
||||
xmm_t A = {0};
|
||||
xmm_t B = {'/', '/', '/', '/', '/', '/', '/', '/',
|
||||
'/', '/', '/', '/', '/', '/', '/', '/'};
|
||||
xmm_t C = {'"', '"', '"', '"', '"', '"', '"', '"',
|
||||
'"', '"', '"', '"', '"', '"', '"', '"'};
|
||||
xmm_t D = {'\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\',
|
||||
'\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\'};
|
||||
xmm_t E = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
|
||||
'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
|
||||
for (;;) {
|
||||
v = *(const xmm_t *)(p + i);
|
||||
m = __builtin_ia32_pmovmskb128((v == A) | (v == B) | (v == C) |
|
||||
(v == D) | (v == E));
|
||||
if (!m) {
|
||||
*(xmm_u *)(p + j) = v;
|
||||
i += 16;
|
||||
j += 16;
|
||||
} else {
|
||||
m = bsf(m);
|
||||
memmove(p + j, p + i, m);
|
||||
i += m;
|
||||
j += m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (p[i]) {
|
||||
if (instring) {
|
||||
if (p[i] == '"' && p[i - 1] != '\\') {
|
||||
instring = false;
|
||||
|
@ -100,6 +166,9 @@ void remove_backslash_newline(char *p) {
|
|||
} else {
|
||||
p[j++] = p[i++];
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; n > 0; n--) p[j++] = '\n';
|
||||
p[j] = '\0';
|
||||
|
|
24
third_party/chibicc/hashmap.c
vendored
24
third_party/chibicc/hashmap.c
vendored
|
@ -1,13 +1,18 @@
|
|||
// This is an implementation of the open-addressing hash table.
|
||||
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
#define INIT_SIZE 16 // initial hash bucket size
|
||||
#define LOW_WATERMARK 50 // keep usage below 50% after rehashing
|
||||
#define HIGH_WATERMARK 70 // perform rehash when usage exceeds 70%
|
||||
#define LOW_WATERMARK 20 // keep usage below 50% after rehashing
|
||||
#define HIGH_WATERMARK 40 // perform rehash when usage exceeds 70%
|
||||
#define TOMBSTONE ((void *)-1) // represents deleted hash table entry
|
||||
|
||||
static uint64_t fnv_hash(char *s, int len) {
|
||||
long chibicc_hashmap_hits;
|
||||
long chibicc_hashmap_miss;
|
||||
|
||||
static inline uint64_t fnv_hash(char *s, int len) {
|
||||
return crc32c(0, s, len);
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
for (int i = 0; i < len; i++) {
|
||||
hash *= 0x100000001b3;
|
||||
|
@ -44,8 +49,17 @@ static void rehash(HashMap *map) {
|
|||
}
|
||||
|
||||
static bool match(HashEntry *ent, char *key, int keylen) {
|
||||
return ent->key && ent->key != TOMBSTONE && ent->keylen == keylen &&
|
||||
memcmp(ent->key, key, keylen) == 0;
|
||||
if (ent->key && ent->key != TOMBSTONE) {
|
||||
if (ent->keylen == keylen && !memcmp(ent->key, key, keylen)) {
|
||||
++chibicc_hashmap_hits;
|
||||
return true;
|
||||
} else {
|
||||
++chibicc_hashmap_miss;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
|
||||
|
|
651
third_party/chibicc/help.txt
vendored
Normal file
651
third_party/chibicc/help.txt
vendored
Normal file
|
@ -0,0 +1,651 @@
|
|||
SYNOPSIS
|
||||
|
||||
chibicc.com [FLAGS] INPUTS
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
chibicc - A Small GNU-Style ISO/IEC 9899:2011 Standard Compiler
|
||||
|
||||
OVERVIEW
|
||||
|
||||
chibicc is the simplest/tiniest/hackable/readable c11 compiler in the
|
||||
world that can compile code quickly and consistently across platforms
|
||||
|
||||
FLAGS
|
||||
|
||||
-o PATH
|
||||
|
||||
Specifies path of output.
|
||||
|
||||
-c
|
||||
|
||||
Objectify the source file, but do not link.
|
||||
|
||||
-S
|
||||
|
||||
Compile the source file, but do not objectify.
|
||||
|
||||
-E
|
||||
|
||||
Preprocess the source file, but do not compile.
|
||||
Output defaults to stdout.
|
||||
|
||||
-D TOKEN[=VALUE]
|
||||
|
||||
Defines preprocessor token.
|
||||
|
||||
-U TOKEN
|
||||
|
||||
Undefines preprocessor token.
|
||||
|
||||
-include DIR
|
||||
|
||||
Add include.
|
||||
|
||||
-I DIR
|
||||
-iquote DIR
|
||||
-isystem DIR
|
||||
|
||||
Adds include directory.
|
||||
|
||||
-x c (default for .c files)
|
||||
-x assembler (default for .s files)
|
||||
-x assembler-with-cpp (default for .S files)
|
||||
|
||||
Explicitly specifies programming language.
|
||||
|
||||
-Wa arg1[,arg2...]
|
||||
-Xassembler arg1[,arg2...]
|
||||
|
||||
Appends opaque arguments passed along to assembler.
|
||||
|
||||
-Wl arg1[,arg2...]
|
||||
-Xlinker arg1[,arg2...]
|
||||
|
||||
Appends opaque arguments passed along to linker.
|
||||
|
||||
-v
|
||||
|
||||
Enables verbose mode.
|
||||
Lines with subprocess commands start with a space.
|
||||
|
||||
-###
|
||||
|
||||
Implies -v and enables shell command argument quoting.
|
||||
|
||||
--version
|
||||
|
||||
Shows compiler version.
|
||||
|
||||
--help
|
||||
|
||||
Shows this information.
|
||||
|
||||
|
||||
CODEGEN
|
||||
|
||||
-pg
|
||||
-mfentry
|
||||
-mnop-mcount
|
||||
-mrecord-mcount
|
||||
|
||||
Controls output of profiling hooks in function prologues.
|
||||
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
|
||||
Controls granularity of code visible to the linker.
|
||||
|
||||
-msse3
|
||||
-msse4
|
||||
-msse4.1
|
||||
-msse4.2
|
||||
-mpopcnt
|
||||
|
||||
Specifies microarchitectural features. Default is K8.
|
||||
|
||||
-fpie
|
||||
-fpic
|
||||
-fPIC
|
||||
|
||||
Controls output of position independent code.
|
||||
|
||||
-fcommon
|
||||
-fno-common
|
||||
|
||||
Controls usage of traditional STT_COMMON objects.
|
||||
|
||||
|
||||
MAKEFILE
|
||||
|
||||
-M
|
||||
|
||||
Generate makefile header dependency code.
|
||||
Output defaults to stdout.
|
||||
|
||||
-MD
|
||||
|
||||
Generate makefile header dependency code, and compile.
|
||||
Output defaults to output path with .d extension.
|
||||
|
||||
-MMD
|
||||
|
||||
Generate makefile header dependency code, and compile.
|
||||
Default include roots are excluded as dependencies.
|
||||
Output defaults to output path with .d extension.
|
||||
|
||||
-MF PATH
|
||||
|
||||
Specifies output path of header dependency code.
|
||||
|
||||
-MT NAME
|
||||
|
||||
Specifies name of target in generated makefile code.
|
||||
|
||||
-MQ NAME
|
||||
|
||||
Specifies name of target in makefile code w/ quoting.
|
||||
|
||||
|
||||
INTERNALS
|
||||
|
||||
-P
|
||||
|
||||
Generate Python bindings.
|
||||
|
||||
-A
|
||||
|
||||
Print abstract syntax tree.
|
||||
|
||||
-J
|
||||
|
||||
Generate HTML documentation for public APIs based on Javadoc
|
||||
comments containing Markdown.
|
||||
|
||||
|
||||
INTEGRAL TYPES
|
||||
|
||||
_Bool
|
||||
char
|
||||
short
|
||||
int
|
||||
long
|
||||
long long
|
||||
__int128
|
||||
signed char
|
||||
unsigned char
|
||||
unsigned short
|
||||
unsigned int
|
||||
unsigned long
|
||||
unsigned long long
|
||||
unsigned __int128
|
||||
|
||||
FLOATING POINT TYPES
|
||||
|
||||
float
|
||||
double
|
||||
long double
|
||||
|
||||
|
||||
BUILTIN FUNCTIONS
|
||||
|
||||
T __builtin_expect(T, int)
|
||||
unsigned long __builtin_offsetof(typename, token)
|
||||
int __builtin_reg_class(typename)
|
||||
num __builtin_constant_p(expr)
|
||||
int __builtin_unreachable()
|
||||
void * __builtin_frame_address(int)
|
||||
_Bool __builtin_types_compatible_p(typename, typename)
|
||||
T __builtin_compare_and_swap(T *addr, T old, T neu)
|
||||
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)
|
||||
int __builtin_clzl(long)
|
||||
int __builtin_clzll(long long)
|
||||
int __builtin_ctz(int)
|
||||
int __builtin_ctzl(long)
|
||||
int __builtin_ctzll(long long)
|
||||
int __builtin_ffs(int)
|
||||
int __builtin_ffsl(long)
|
||||
int __builtin_ffsll(long long)
|
||||
int __builtin_popcount(unsigned int)
|
||||
long __builtin_popcountl(unsigned long)
|
||||
long __builtin_popcountll(unsigned long)
|
||||
unsigned long __builtin_strlen(char *)
|
||||
char * __builtin_strstr(char *, char *)
|
||||
char * __builtin_strchr(char *, int)
|
||||
void * __builtin_memcpy(void *, void *, unsigned long)
|
||||
char * __builtin_strpbrk(char *, char *)
|
||||
unsigned short __builtin_bswap16(unsigned short)
|
||||
unsigned int __builtin_bswap32(unsigned int)
|
||||
unsigned long __builtin_bswap64(unsigned long)
|
||||
int __builtin_isnan(flonum)
|
||||
int __builtin_isinf(flonum)
|
||||
int __builtin_isfinite(flonum)
|
||||
int __builtin_fpclassify(flonum)
|
||||
int __builtin_isless(flonum, flonum)
|
||||
int __builtin_isgreater(flonum, flonum)
|
||||
int __builtin_isunordered(flonum, flonum)
|
||||
int __builtin_islessequal(flonum, flonum)
|
||||
int __builtin_islessgreater(flonum, flonum)
|
||||
int __builtin_isgreaterequal(flonum, flonum)
|
||||
double __builtin_nan(char *)
|
||||
float __builtin_nanf(char *)
|
||||
long double __builtin_nanl(char *)
|
||||
long __builtin_signbit(double)
|
||||
int __builtin_signbitf(float)
|
||||
int __builtin_signbitl(long double)
|
||||
double __builtin_huge_val()
|
||||
float __builtin_huge_valf()
|
||||
long double __builtin_huge_vall()
|
||||
double __builtin_fabs(double)
|
||||
float __builtin_fabsf(float)
|
||||
long double __builtin_fabsl(long double)
|
||||
double __builtin_logb(double)
|
||||
float __builtin_logbf(float)
|
||||
long double __builtin_logbl(long double)
|
||||
double __builtin_fmax(double, double)
|
||||
float __builtin_fmaxf(float, float)
|
||||
long double __builtin_fmaxl(long double, long double)
|
||||
double __builtin_fmin(double, double)
|
||||
float __builtin_fminf(float, float)
|
||||
long double __builtin_fminl(long double, long double)
|
||||
double __builtin_copysign(double, double)
|
||||
float __builtin_copysignf(float, float)
|
||||
long double __builtin_copysignl(long double, long double)
|
||||
|
||||
|
||||
BUILTIN OBJECTS
|
||||
|
||||
__func__
|
||||
__FUNCTION__
|
||||
__va_area__
|
||||
__alloca_size__
|
||||
|
||||
BUILTIN MACROS
|
||||
|
||||
__FILE__
|
||||
__LINE__
|
||||
__DATE__
|
||||
__TIME__
|
||||
__COUNTER__
|
||||
__TIMESTAMP__
|
||||
__BASE_FILE__
|
||||
__chibicc__
|
||||
__cosmopolitan__
|
||||
__GNUC__
|
||||
__GNUC_MINOR__
|
||||
__GNUC_PATCHLEVEL__
|
||||
__NO_INLINE__
|
||||
__GNUC_STDC_INLINE__
|
||||
__BIGGEST_ALIGNMENT__
|
||||
__C99_MACRO_WITH_VA_ARGS
|
||||
__GCC_ASM_FLAG_OUTPUTS__
|
||||
__ELF__
|
||||
__LP64__
|
||||
_LP64
|
||||
__STDC__
|
||||
__STDC_HOSTED__
|
||||
__STDC_NO_COMPLEX__
|
||||
__STDC_UTF_16__
|
||||
__STDC_UTF_32__
|
||||
__STDC_VERSION__
|
||||
__USER_LABEL_PREFIX__
|
||||
__alignof__
|
||||
__const__
|
||||
__inline__
|
||||
__signed__
|
||||
__typeof__
|
||||
__volatile__
|
||||
__unix
|
||||
__unix__
|
||||
__linux
|
||||
__linux__
|
||||
__gnu_linux__
|
||||
__BYTE_ORDER__
|
||||
__FLOAT_WORD_ORDER__
|
||||
__ORDER_BIG_ENDIAN__
|
||||
__ORDER_LITTLE_ENDIAN__
|
||||
__INT8_MAX__
|
||||
__UINT8_MAX__
|
||||
__INT16_MAX__
|
||||
__UINT16_MAX__
|
||||
__SHRT_MAX__
|
||||
__INT_MAX__
|
||||
__INT32_MAX__
|
||||
__UINT32_MAX__
|
||||
__INT64_MAX__
|
||||
__LONG_MAX__
|
||||
__LONG_LONG_MAX__
|
||||
__UINT64_MAX__
|
||||
__SIZE_MAX__
|
||||
__INTPTR_MAX__
|
||||
__UINTPTR_MAX__
|
||||
__WINT_MAX__
|
||||
__CHAR_BIT__
|
||||
__SIZEOF_SHORT__
|
||||
__SIZEOF_INT__
|
||||
__SIZEOF_LONG__
|
||||
__SIZEOF_LONG_LONG__
|
||||
__SIZEOF_POINTER__
|
||||
__SIZEOF_PTRDIFF_T__
|
||||
__SIZEOF_SIZE_T__
|
||||
__SIZEOF_WCHAR_T__
|
||||
__SIZEOF_WINT_T__
|
||||
__SIZEOF_FLOAT__
|
||||
__SIZEOF_FLOAT128__
|
||||
__SIZEOF_DOUBLE__
|
||||
__SIZEOF_FLOAT80__
|
||||
__SIZEOF_LONG_DOUBLE__
|
||||
__INT8_TYPE__
|
||||
__UINT8_TYPE__
|
||||
__INT16_TYPE__
|
||||
__UINT16_TYPE__
|
||||
__INT32_TYPE__
|
||||
__UINT32_TYPE__
|
||||
__INT64_TYPE__
|
||||
__UINT64_TYPE__
|
||||
__INTPTR_TYPE__
|
||||
__UINTPTR_TYPE__
|
||||
__PTRDIFF_TYPE__
|
||||
__SIZE_TYPE__
|
||||
__WCHAR_TYPE__
|
||||
__CHAR16_TYPE__
|
||||
__CHAR32_TYPE__
|
||||
__WINT_TYPE__
|
||||
__CHAR16_TYPE__
|
||||
__WCHAR_TYPE__
|
||||
__CHAR32_TYPE__
|
||||
__INT_LEAST8_TYPE__
|
||||
__UINT_LEAST8_TYPE__
|
||||
__INT_LEAST16_TYPE__
|
||||
__UINT_LEAST16_TYPE__
|
||||
__INT_LEAST32_TYPE__
|
||||
__UINT_LEAST32_TYPE__
|
||||
__INT_LEAST64_TYPE__
|
||||
__UINT_LEAST64_TYPE__
|
||||
__INT_FAST8_TYPE__
|
||||
__UINT_FAST8_TYPE__
|
||||
__INT_FAST16_TYPE__
|
||||
__UINT_FAST16_TYPE__
|
||||
__INT_FAST32_TYPE__
|
||||
__UINT_FAST32_TYPE__
|
||||
__INT_FAST64_TYPE__
|
||||
__UINT_FAST64_TYPE__
|
||||
__DBL_DECIMAL_DIG__
|
||||
__DBL_DENORM_MIN__
|
||||
__DBL_DIG__
|
||||
__DBL_EPSILON__
|
||||
__DBL_HAS_DENORM__
|
||||
__DBL_HAS_INFINITY__
|
||||
__DBL_HAS_QUIET_NAN__
|
||||
__DBL_MANT_DIG__
|
||||
__DBL_MAX_10_EXP__
|
||||
__DBL_MAX_EXP__
|
||||
__DBL_MAX__
|
||||
__DBL_MIN_10_EXP__
|
||||
__DBL_MIN_EXP__
|
||||
__DBL_MIN__
|
||||
__FLT_DECIMAL_DIG__
|
||||
__FLT_DENORM_MIN__
|
||||
__FLT_DIG__
|
||||
__FLT_EPSILON__
|
||||
__FLT_EVAL_METHOD_TS_18661_3__
|
||||
__FLT_EVAL_METHOD__
|
||||
__FLT_HAS_DENORM__
|
||||
__FLT_HAS_INFINITY__
|
||||
__FLT_HAS_QUIET_NAN__
|
||||
__FLT_MANT_DIG__
|
||||
__FLT_MAX_10_EXP__
|
||||
__FLT_MAX_EXP__
|
||||
__FLT_MAX__
|
||||
__FLT_MIN_10_EXP__
|
||||
__FLT_MIN_EXP__
|
||||
__FLT_MIN__
|
||||
__FLT_RADIX__
|
||||
__LDBL_DECIMAL_DIG__
|
||||
__LDBL_DENORM_MIN__
|
||||
__LDBL_DIG__
|
||||
__LDBL_EPSILON__
|
||||
__LDBL_HAS_DENORM__
|
||||
__LDBL_HAS_INFINITY__
|
||||
__LDBL_HAS_QUIET_NAN__
|
||||
__LDBL_MANT_DIG__
|
||||
__LDBL_MAX_10_EXP__
|
||||
__LDBL_MAX_EXP__
|
||||
__LDBL_MAX__
|
||||
__LDBL_MIN_10_EXP__
|
||||
__LDBL_MIN_EXP__
|
||||
__LDBL_MIN__
|
||||
__x86_64
|
||||
__x86_64__
|
||||
__amd64
|
||||
__amd64__
|
||||
__MMX__
|
||||
__SSE__
|
||||
__SSE_MATH__
|
||||
__SSE2__
|
||||
__SSE2_MATH__
|
||||
__SSE3__ [conditional]
|
||||
__SSE4__ [conditional]
|
||||
__POPCNT__ [conditional]
|
||||
__PG__ [conditional]
|
||||
__PIC__ [conditional]
|
||||
__MFENTRY__ [conditional]
|
||||
|
||||
|
||||
ASSEMBLER
|
||||
|
||||
That process is normally an implementation detail of your compiler,
|
||||
which can embed this program or launch it as a subprocess. Much GNU
|
||||
style syntax is supported. Your code that gets embedded in an asm()
|
||||
statement will ultimately end up here. This implementation, has the
|
||||
advantage of behaving the same across platforms, in a simple single
|
||||
file implementation that compiles down to a 100kilo ape executable.
|
||||
|
||||
Your assembler supports the following flags:
|
||||
|
||||
-o FILE output path [default: a.out]
|
||||
-I DIR append include path [default: .]
|
||||
-W inhibit .warning
|
||||
-Z inhibit .error and .err
|
||||
|
||||
Your assembler supports the following directives:
|
||||
|
||||
.zero N emits 0's
|
||||
.byte INT... emits int8
|
||||
.word INT... emits int16
|
||||
.long INT... emits int32
|
||||
.quad INT... emits int64
|
||||
.octa INT... emits int128
|
||||
.ascii STR... emits string
|
||||
.asciz STR... emits string and 0 byte
|
||||
.ident STR emits string to .comment section
|
||||
.float NUMBER... emits binary32
|
||||
.double NUMBER... emits binary64
|
||||
.float80 NUMBER... emits x86 float (10 bytes)
|
||||
.ldbl NUMBER... emits x86 float (16 bytes)
|
||||
.zleb128 NUMBER... emits LEB-128 zigzag varint
|
||||
.sleb128 NUMBER... emits LEB-128 signed varint
|
||||
.uleb128 NUMBER... emits LEB-128 unsigned varint
|
||||
.align BYTES [FILL [MAXSKIP]] emits fill bytes to boundary
|
||||
.end halts tokenization
|
||||
.abort crashes assembler
|
||||
.err aborts (ignorable w/ -Z)
|
||||
.error STR aborts (ignorable w/ -Z)
|
||||
.warning STR whines (ignorable w/ -W)
|
||||
.text enters text section (default)
|
||||
.data enters data section
|
||||
.bss enters bss section
|
||||
.section NAME [SFLG SHT] enters section
|
||||
.previous enters previous section
|
||||
.pushsection NAME [SFLG SHT] pushes section
|
||||
.popsection pops section
|
||||
.type SYM TYPE sets type of symbol
|
||||
.size SYM EXPR sets size of symbol
|
||||
.internal SYM... marks symbol STV_INTERNAL
|
||||
.hidden SYM... marks symbol STV_HIDDEN
|
||||
.protected SYM... marks symbol STV_PROTECTED
|
||||
.globl SYM... marks symbol STB_GLOBAL
|
||||
.local SYM... marks symbol STB_LOCAL
|
||||
.weak SYM... marks symbol STB_WEAK
|
||||
.include FILE assembles file source
|
||||
.incbin FILE emits file content
|
||||
.file FILENO PATH dwarf file define
|
||||
.loc FILENO LINENO dwarf source line
|
||||
|
||||
TYPE can be one of the following:
|
||||
|
||||
- @notype STT_NOTYPE (default)
|
||||
- @object STT_OBJECT
|
||||
- @function STT_FUNC
|
||||
- @common STT_COMMON
|
||||
- @tls_object STT_TLS
|
||||
|
||||
SHT can be one of the following:
|
||||
|
||||
- @progbits SHT_PROGBITS
|
||||
- @note SHT_NOTE
|
||||
- @nobits SHT_NOBITS
|
||||
- @preinit_array SHT_PREINIT_ARRAY
|
||||
- @init_array SHT_INIT_ARRAY
|
||||
- @fini_array SHT_FINI_ARRAY
|
||||
|
||||
SFLG is a string which may have the following characters:
|
||||
|
||||
- a SHF_ALLOC
|
||||
- w SHF_WRITE
|
||||
- x SHF_EXECINSTR
|
||||
- g SHF_GROUP
|
||||
- M SHF_MERGE
|
||||
- S SHF_STRINGS
|
||||
- T SHF_TLS
|
||||
|
||||
PREFIXES
|
||||
|
||||
addr32 cs data16 ds es fs
|
||||
gs lock rep repe repne repnz
|
||||
repz rex rex.b rex.r rex.rb rex.rx
|
||||
rex.rxb rex.w rex.wb rex.wr rex.wrb rex.wrx
|
||||
rex.wrxb rex.wx rex.wxb rex.x rex.xb ss
|
||||
|
||||
REGISTERS
|
||||
|
||||
64-bit 32-bit 16-bit lo byte hi byte │ sse mmx │ fpu
|
||||
─────── ─────── ─────── ─────── ─────── │ ─────── ─────── │ ───────
|
||||
%rax %eax %ax %al %ah │ %xmm0 %mm0 │ %st(0)
|
||||
%rcx %ecx %cx %cl %ch │ %xmm1 %mm1 │ %st(1)
|
||||
%rdx %edx %dx %dl %dh │ %xmm2 %mm2 │ %st(2)
|
||||
%rbx %ebx %bx %bl %bh │ %xmm3 %mm3 │ %st(3)
|
||||
%rsp %esp %sp %spl │ %xmm4 %mm4 │ %st(4)
|
||||
%rbp %ebp %bp %bpl │ %xmm5 %mm5 │ %st(5)
|
||||
%rsi %esi %si %sil │ %xmm6 %mm6 │ %st(6)
|
||||
%rdi %edi %di %dil │ %xmm7 %mm7 │ %st(7)
|
||||
%r8 %r8d %r8w %r8b │ %xmm8
|
||||
%r9 %r9d %r9w %r9b │ %xmm9
|
||||
%r10 %r10d %r10w %r10b │ %xmm10
|
||||
%r11 %r11d %r11w %r11b │ %xmm11
|
||||
%r12 %r12d %r12w %r12b │ %xmm12
|
||||
%r13 %r13d %r13w %r13b │ %xmm13
|
||||
%r14 %r14d %r14w %r14b │ %xmm14
|
||||
%r15 %r15d %r15w %r15b │ %xmm15
|
||||
%riz %eiz
|
||||
|
||||
|
||||
RICHARD STALLMAN MATH55 ASM() NOTATION
|
||||
|
||||
BEHAVIOR
|
||||
|
||||
=: write-only
|
||||
+: read/writeable
|
||||
|
||||
SELECTION
|
||||
|
||||
Autonomous
|
||||
|
||||
a: ax/eax/rax
|
||||
b: bx/ebx/rbx
|
||||
c: bx/ebx/rbx
|
||||
d: dx/edx/rdx
|
||||
S: si/esi/rsi
|
||||
D: di/edi/rdi
|
||||
|
||||
Algorithmic
|
||||
|
||||
r: pick one of a,b,c,d,D,S,bp,sp,r8-15 registers, referenced as %0,etc.
|
||||
l: pick one of a,b,c,d,D,S,bp,r8-15 for indexing, referenced as %0,etc.
|
||||
q: pick one of a,b,c,d,r8-r15 for lo-byte access, e.g. %b0,%w0,%k0,etc.
|
||||
Q: pick one of a,b,c,d for hi-byte access, e.g. %h0,etc.
|
||||
U: pick one of a,c,d,D,S,r8-11 (call-clobbered)
|
||||
R: pick one of a,b,c,d,D,S,bp,sp (all models)
|
||||
y: pick mmx register
|
||||
x: pick sse register
|
||||
X: pick anything
|
||||
m: memory
|
||||
o: memory offsetable by an immediate, referenced as %0,2+%0,etc.
|
||||
p: memory, intended for load/push address and segments (movl %@:%p1, %0)
|
||||
g: probably shorthand for "rmi" combo
|
||||
X: allow anything
|
||||
|
||||
Combos
|
||||
|
||||
rm: pick register or memory address (converting immediates)
|
||||
rmi: pick register or memory address (allowing immediates)
|
||||
|
||||
Immediates
|
||||
|
||||
i: integer literal or compiler/assembler constexpr or linker embedding
|
||||
e: i∊[-2^31,2^31) for sign-extending immediates
|
||||
Z: i∊[0,2^32) for zero-extending immediates
|
||||
I: i∊[0,31] (5 bits for 32-bit shifts)
|
||||
J: i∊[0,63] (6 bits for 64-bit shifts)
|
||||
K: i∊[-128,127]
|
||||
L: permit uncasted char/short literal as zero-extended operand to andl?
|
||||
M: i∊[0,3] (intended for index scaling, e.g. "mov\t(?,?,1<<%0),?")
|
||||
N: i∊[0,255] (for in & out)
|
||||
M: 2-bit integer constant (shifts for index scaling)
|
||||
I: 5-bit integer constant (for 32-bit shifts)
|
||||
J: 6-bit integer constant (for 64-bit shifts)
|
||||
|
||||
Transcendentals
|
||||
|
||||
f: any stack slot
|
||||
t: top of stack (%st(0)) and possibly converts xmm to ymm
|
||||
u: second top of stack (%st(1))
|
||||
|
||||
Specials
|
||||
|
||||
%= generates number unique to each instance
|
||||
%%REG explicitly-supplied register (used w/ clobbers)
|
||||
|
||||
AUGMENTATION
|
||||
|
||||
%pN print raw
|
||||
%PN print w/ @plt
|
||||
%aN print address
|
||||
%zN print only opcode suffix for operand type
|
||||
%lN print label without punctuation, e.g. jumps
|
||||
%cN print immediate w/o punctuation, e.g. lea %c0(%1),%2
|
||||
%bN print lo-byte form, e.g. xchgb %b0,%%al (QImode 8-bit)
|
||||
%hN print hi-byte form, e.g. xchgb %h0,%%ah (QImode 8-bit)
|
||||
%wN print word form, e.g. xchgw %w0,%%ax (HImode 16-bit)
|
||||
%kN print dword form, e.g. xchgl %k0,%%eax (SImode 32-bit)
|
||||
%qN print qword form, e.g. xchgq %q0,%%rax (DImode 64-bit)
|
||||
%HN access high 8 bytes of SSE register, or +8 displacement
|
||||
%nN negated literal, e.g. lea %n0(%1),%2
|
||||
%VN print register name without %, e.g. call foo%V0
|
||||
|
||||
EXAMPLE
|
||||
|
||||
static inline void MixAudio(short a[static 8], const short b[static 8]) {
|
||||
asm("paddsw\t%1,%0"
|
||||
: "+x"(a)
|
||||
: "x"(b)
|
||||
: "memory");
|
||||
}
|
33
third_party/chibicc/kw.c
vendored
Normal file
33
third_party/chibicc/kw.c
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
#include "third_party/chibicc/kw.h"
|
||||
#include "third_party/chibicc/kw.inc"
|
||||
|
||||
/**
|
||||
* Returns small number for HTTP header, or -1 if not found.
|
||||
*/
|
||||
unsigned char GetKw(const char *str, size_t len) {
|
||||
const struct KwSlot *slot;
|
||||
if ((slot = LookupKw(str, len))) {
|
||||
return slot->code;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
120
third_party/chibicc/kw.gperf
vendored
Normal file
120
third_party/chibicc/kw.gperf
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
%{
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/chibicc/kw.h"
|
||||
%}
|
||||
%compare-strncmp
|
||||
%language=ANSI-C
|
||||
%readonly-tables
|
||||
%struct-type
|
||||
%define lookup-function-name LookupKw
|
||||
struct thatispacked KwSlot { char *name; unsigned char code; };
|
||||
%%
|
||||
if, KW_IF
|
||||
struct, KW_STRUCT
|
||||
return, KW_RETURN
|
||||
case, KW_CASE
|
||||
static, KW_STATIC
|
||||
void, KW_VOID
|
||||
char, KW_CHAR
|
||||
else, KW_ELSE
|
||||
for, KW_FOR
|
||||
do, KW_DO
|
||||
sizeof, KW_SIZEOF
|
||||
unsigned, KW_UNSIGNED
|
||||
long, KW_LONG
|
||||
while, KW_WHILE
|
||||
union, KW_UNION
|
||||
switch, KW_SWITCH
|
||||
double, KW_DOUBLE
|
||||
const, KW_CONST
|
||||
float, KW_FLOAT
|
||||
short, KW_SHORT
|
||||
signed, KW_SIGNED
|
||||
break, KW_BREAK
|
||||
enum, KW_ENUM
|
||||
continue, KW_CONTINUE
|
||||
include, KW_INCLUDE
|
||||
ifdef, KW_IFDEF
|
||||
ifndef, KW_IFNDEF
|
||||
define, KW_DEFINE
|
||||
defined, KW_DEFINED
|
||||
asm, KW_ASM
|
||||
default, KW_DEFAULT
|
||||
auto, KW_AUTO
|
||||
register, KW_REGISTER
|
||||
__attribute__, KW___ATTRIBUTE__
|
||||
_Noreturn, KW__NORETURN
|
||||
elif, KW_ELIF
|
||||
endif, KW_ENDIF
|
||||
error, KW_ERROR
|
||||
extern, KW_EXTERN
|
||||
goto, KW_GOTO
|
||||
include_next, KW_INCLUDE_NEXT
|
||||
inline, KW_INLINE
|
||||
int, KW_INT
|
||||
line, KW_LINE
|
||||
pragma, KW_PRAGMA
|
||||
restrict, KW_RESTRICT
|
||||
strchr, KW_STRCHR
|
||||
strlen, KW_STRLEN
|
||||
strpbrk, KW_STRPBRK
|
||||
strstr, KW_STRSTR
|
||||
typedef, KW_TYPEDEF
|
||||
typeof, KW_TYPEOF
|
||||
undef, KW_UNDEF
|
||||
volatile, KW_VOLATILE
|
||||
_Alignas, KW__ALIGNAS
|
||||
_Alignof, KW__ALIGNOF
|
||||
_Atomic, KW__ATOMIC
|
||||
_Bool, KW__BOOL
|
||||
_Generic, KW__GENERIC
|
||||
_Static_assert, KW__STATIC_ASSERT
|
||||
_Thread_local, KW__THREAD_LOCAL
|
||||
__VA_OPT__, KW___VA_OPT__
|
||||
__alignof__, KW___ALIGNOF__
|
||||
__asm__, KW___ASM__
|
||||
__inline, KW_INLINE
|
||||
__int128, KW___INT128
|
||||
__restrict, KW_RESTRICT
|
||||
__restrict__, KW_RESTRICT
|
||||
__thread, KW__THREAD_LOCAL
|
||||
__typeof, KW_TYPEOF
|
||||
__builtin_add_overflow, KW___BUILTIN_ADD_OVERFLOW
|
||||
__builtin_assume_aligned, KW___BUILTIN_ASSUME_ALIGNED
|
||||
__builtin_atomic_exchange, KW___BUILTIN_ATOMIC_EXCHANGE
|
||||
__builtin_compare_and_swap, KW___BUILTIN_COMPARE_AND_SWAP
|
||||
__builtin_constant_p, KW___BUILTIN_CONSTANT_P
|
||||
__builtin_expect, KW___BUILTIN_EXPECT
|
||||
__builtin_ffs, KW___BUILTIN_FFS
|
||||
__builtin_ffsl, KW___BUILTIN_FFSL
|
||||
__builtin_ffsll, KW___BUILTIN_FFSLL
|
||||
__builtin_fpclassify, KW___BUILTIN_FPCLASSIFY
|
||||
__builtin_mul_overflow, KW___BUILTIN_MUL_OVERFLOW
|
||||
__builtin_neg_overflow, KW___BUILTIN_NEG_OVERFLOW
|
||||
__builtin_offsetof, KW___BUILTIN_OFFSETOF
|
||||
__builtin_popcount, KW___BUILTIN_POPCOUNT
|
||||
__builtin_popcountl, KW___BUILTIN_POPCOUNTL
|
||||
__builtin_popcountll, KW___BUILTIN_POPCOUNTLL
|
||||
__builtin_reg_class, KW___BUILTIN_REG_CLASS
|
||||
__builtin_strchr, KW___BUILTIN_STRCHR
|
||||
__builtin_strlen, KW___BUILTIN_STRLEN
|
||||
__builtin_strpbrk, KW___BUILTIN_STRPBRK
|
||||
__builtin_strstr, KW___BUILTIN_STRSTR
|
||||
__builtin_sub_overflow, KW___BUILTIN_SUB_OVERFLOW
|
||||
__builtin_types_compatible_p, KW___BUILTIN_TYPES_COMPATIBLE_P
|
||||
"(", KW_LP
|
||||
")", KW_RP
|
||||
"{", KW_LB
|
||||
"}", KW_RB
|
||||
"+", KW_PLUS
|
||||
"-", KW_MINUS
|
||||
"&", KW_AMP
|
||||
"*", KW_STAR
|
||||
"!", KW_EXCLAIM
|
||||
"~", KW_TILDE
|
||||
"++", KW_INCREMENT
|
||||
"--", KW_DECREMENT
|
||||
"&&", KW_LOGAND
|
||||
"||", KW_LOGOR
|
||||
"->", KW_ARROW
|
||||
".", KW_DOT
|
116
third_party/chibicc/kw.h
vendored
Normal file
116
third_party/chibicc/kw.h
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_KW_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_KW_H_
|
||||
|
||||
#define KW_STRUCT 1 /* keyword typename */
|
||||
#define KW_STATIC 2 /* keyword typename */
|
||||
#define KW_VOID 3 /* keyword typename */
|
||||
#define KW_CHAR 4 /* keyword typename */
|
||||
#define KW_UNSIGNED 5 /* keyword typename */
|
||||
#define KW_LONG 6 /* keyword typename */
|
||||
#define KW_UNION 7 /* keyword typename */
|
||||
#define KW_DOUBLE 8 /* keyword typename */
|
||||
#define KW_CONST 9 /* keyword typename */
|
||||
#define KW_FLOAT 10 /* keyword typename */
|
||||
#define KW_SHORT 11 /* keyword typename */
|
||||
#define KW_SIGNED 12 /* keyword typename */
|
||||
#define KW_ENUM 13 /* keyword typename */
|
||||
#define KW_AUTO 14 /* keyword typename */
|
||||
#define KW_REGISTER 15 /* keyword typename */
|
||||
#define KW__NORETURN 16 /* keyword typename */
|
||||
#define KW_EXTERN 17 /* keyword typename */
|
||||
#define KW_INLINE 18 /* keyword typename */
|
||||
#define KW_INT 19 /* keyword typename */
|
||||
#define KW_RESTRICT 20 /* keyword typename */
|
||||
#define KW_TYPEDEF 21 /* keyword typename */
|
||||
#define KW_TYPEOF 22 /* keyword typename */
|
||||
#define KW_VOLATILE 23 /* keyword typename */
|
||||
#define KW__ALIGNAS 24 /* keyword typename */
|
||||
#define KW__ATOMIC 25 /* keyword typename */
|
||||
#define KW__BOOL 26 /* keyword typename */
|
||||
#define KW__THREAD_LOCAL 27 /* keyword typename */
|
||||
#define KW___INT128 28 /* keyword typename */
|
||||
#define KW_IF 33 /* keyword */
|
||||
#define KW_RETURN 34 /* keyword */
|
||||
#define KW_CASE 35 /* keyword */
|
||||
#define KW_ELSE 36 /* keyword */
|
||||
#define KW_FOR 37 /* keyword */
|
||||
#define KW_DO 38 /* keyword */
|
||||
#define KW_SIZEOF 39 /* keyword */
|
||||
#define KW_WHILE 40 /* keyword */
|
||||
#define KW_SWITCH 41 /* keyword */
|
||||
#define KW_BREAK 42 /* keyword */
|
||||
#define KW_CONTINUE 43 /* keyword */
|
||||
#define KW_ASM 44 /* keyword */
|
||||
#define KW_DEFAULT 45 /* keyword */
|
||||
#define KW___ATTRIBUTE__ 46 /* keyword */
|
||||
#define KW_GOTO 47 /* keyword */
|
||||
#define KW__ALIGNOF 48 /* keyword */
|
||||
#define KW_INCLUDE 64
|
||||
#define KW_IFDEF 65
|
||||
#define KW_IFNDEF 66
|
||||
#define KW_DEFINE 67
|
||||
#define KW_DEFINED 68
|
||||
#define KW_ELIF 69
|
||||
#define KW_ENDIF 70
|
||||
#define KW_ERROR 71
|
||||
#define KW_INCLUDE_NEXT 72
|
||||
#define KW_LINE 73
|
||||
#define KW_PRAGMA 74
|
||||
#define KW_STRCHR 75
|
||||
#define KW_STRLEN 76
|
||||
#define KW_STRPBRK 77
|
||||
#define KW_STRSTR 78
|
||||
#define KW_UNDEF 79
|
||||
#define KW__GENERIC 80
|
||||
#define KW__STATIC_ASSERT 81
|
||||
#define KW___VA_OPT__ 82
|
||||
#define KW___ALIGNOF__ 83
|
||||
#define KW___ASM__ 84
|
||||
#define KW___BUILTIN_ADD_OVERFLOW 85
|
||||
#define KW___BUILTIN_ASSUME_ALIGNED 86
|
||||
#define KW___BUILTIN_ATOMIC_EXCHANGE 87
|
||||
#define KW___BUILTIN_COMPARE_AND_SWAP 88
|
||||
#define KW___BUILTIN_CONSTANT_P 89
|
||||
#define KW___BUILTIN_EXPECT 90
|
||||
#define KW___BUILTIN_FFS 91
|
||||
#define KW___BUILTIN_FFSL 92
|
||||
#define KW___BUILTIN_FFSLL 93
|
||||
#define KW___BUILTIN_FPCLASSIFY 94
|
||||
#define KW___BUILTIN_MUL_OVERFLOW 95
|
||||
#define KW___BUILTIN_NEG_OVERFLOW 96
|
||||
#define KW___BUILTIN_OFFSETOF 97
|
||||
#define KW___BUILTIN_POPCOUNT 98
|
||||
#define KW___BUILTIN_POPCOUNTL 99
|
||||
#define KW___BUILTIN_POPCOUNTLL 100
|
||||
#define KW___BUILTIN_REG_CLASS 101
|
||||
#define KW___BUILTIN_STRCHR 102
|
||||
#define KW___BUILTIN_STRLEN 103
|
||||
#define KW___BUILTIN_STRPBRK 104
|
||||
#define KW___BUILTIN_STRSTR 105
|
||||
#define KW___BUILTIN_SUB_OVERFLOW 106
|
||||
#define KW___BUILTIN_TYPES_COMPATIBLE_P 107
|
||||
#define KW_LP 108
|
||||
#define KW_RP 109
|
||||
#define KW_LB 110
|
||||
#define KW_RB 111
|
||||
#define KW_PLUS 112
|
||||
#define KW_MINUS 113
|
||||
#define KW_AMP 114
|
||||
#define KW_STAR 115
|
||||
#define KW_EXCLAIM 116
|
||||
#define KW_TILDE 117
|
||||
#define KW_INCREMENT 118
|
||||
#define KW_DECREMENT 119
|
||||
#define KW_LOGAND 120
|
||||
#define KW_LOGOR 121
|
||||
#define KW_ARROW 122
|
||||
#define KW_DOT 123
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
unsigned char GetKw(const char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_KW_H_ */
|
395
third_party/chibicc/kw.inc
vendored
Normal file
395
third_party/chibicc/kw.inc
vendored
Normal file
|
@ -0,0 +1,395 @@
|
|||
/* ANSI-C code produced by gperf version 3.1 */
|
||||
/* Command-line: gperf kw.gperf */
|
||||
/* Computed positions: -k'1,4,11,14,$' */
|
||||
/* clang-format off */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
||||
/* The character set is not based on ISO-646. */
|
||||
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
|
||||
#endif
|
||||
|
||||
#line 1 "kw.gperf"
|
||||
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/chibicc/kw.h"
|
||||
#line 10 "kw.gperf"
|
||||
struct thatispacked KwSlot { char *name; unsigned char code; };
|
||||
|
||||
#define TOTAL_KEYWORDS 109
|
||||
#define MIN_WORD_LENGTH 1
|
||||
#define MAX_WORD_LENGTH 28
|
||||
#define MIN_HASH_VALUE 1
|
||||
#define MAX_HASH_VALUE 211
|
||||
/* maximum key range = 211, duplicates = 0 */
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static unsigned int
|
||||
hash (register const char *str, register size_t len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 105, 212, 212, 212, 212, 65, 212,
|
||||
100, 95, 90, 15, 212, 0, 80, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 5, 212, 212, 212,
|
||||
212, 212, 65, 212, 212, 212, 0, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 5, 212, 20, 50, 0,
|
||||
5, 15, 0, 25, 40, 90, 60, 0, 20, 15,
|
||||
85, 105, 0, 25, 55, 10, 0, 65, 5, 0,
|
||||
0, 10, 0, 30, 10, 25, 5, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
|
||||
212, 212, 212, 212, 212, 212, 212
|
||||
};
|
||||
register unsigned int hval = len;
|
||||
|
||||
switch (hval)
|
||||
{
|
||||
default:
|
||||
hval += asso_values[(unsigned char)str[13]];
|
||||
/*FALLTHROUGH*/
|
||||
case 13:
|
||||
case 12:
|
||||
case 11:
|
||||
hval += asso_values[(unsigned char)str[10]];
|
||||
/*FALLTHROUGH*/
|
||||
case 10:
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
hval += asso_values[(unsigned char)str[3]+1];
|
||||
/*FALLTHROUGH*/
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
hval += asso_values[(unsigned char)str[0]];
|
||||
break;
|
||||
}
|
||||
return hval + asso_values[(unsigned char)str[len - 1]];
|
||||
}
|
||||
|
||||
static inline const struct thatispacked KwSlot *
|
||||
LookupKw (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct thatispacked KwSlot wordlist[] =
|
||||
{
|
||||
{""},
|
||||
#line 110 "kw.gperf"
|
||||
{"-", KW_MINUS},
|
||||
#line 116 "kw.gperf"
|
||||
{"--", KW_DECREMENT},
|
||||
{""}, {""},
|
||||
#line 29 "kw.gperf"
|
||||
{"const", KW_CONST},
|
||||
#line 63 "kw.gperf"
|
||||
{"typeof", KW_TYPEOF},
|
||||
#line 62 "kw.gperf"
|
||||
{"typedef", KW_TYPEDEF},
|
||||
{""}, {""}, {""},
|
||||
#line 114 "kw.gperf"
|
||||
{"~", KW_TILDE},
|
||||
#line 68 "kw.gperf"
|
||||
{"_Atomic", KW__ATOMIC},
|
||||
#line 81 "kw.gperf"
|
||||
{"__typeof", KW_TYPEOF},
|
||||
{""},
|
||||
#line 78 "kw.gperf"
|
||||
{"__restrict", KW_RESTRICT},
|
||||
#line 22 "kw.gperf"
|
||||
{"sizeof", KW_SIZEOF},
|
||||
#line 75 "kw.gperf"
|
||||
{"__asm__", KW___ASM__},
|
||||
{""},
|
||||
#line 15 "kw.gperf"
|
||||
{"case", KW_CASE},
|
||||
#line 73 "kw.gperf"
|
||||
{"__VA_OPT__", KW___VA_OPT__},
|
||||
#line 13 "kw.gperf"
|
||||
{"struct", KW_STRUCT},
|
||||
#line 118 "kw.gperf"
|
||||
{"||", KW_LOGOR},
|
||||
{""}, {""},
|
||||
#line 31 "kw.gperf"
|
||||
{"short", KW_SHORT},
|
||||
#line 28 "kw.gperf"
|
||||
{"double", KW_DOUBLE},
|
||||
#line 79 "kw.gperf"
|
||||
{"__restrict__", KW_RESTRICT},
|
||||
#line 95 "kw.gperf"
|
||||
{"__builtin_popcount", KW___BUILTIN_POPCOUNT},
|
||||
#line 17 "kw.gperf"
|
||||
{"void", KW_VOID},
|
||||
#line 69 "kw.gperf"
|
||||
{"_Bool", KW__BOOL},
|
||||
#line 109 "kw.gperf"
|
||||
{"+", KW_PLUS},
|
||||
#line 115 "kw.gperf"
|
||||
{"++", KW_INCREMENT},
|
||||
#line 88 "kw.gperf"
|
||||
{"__builtin_ffs", KW___BUILTIN_FFS},
|
||||
#line 19 "kw.gperf"
|
||||
{"else", KW_ELSE},
|
||||
#line 25 "kw.gperf"
|
||||
{"while", KW_WHILE},
|
||||
#line 85 "kw.gperf"
|
||||
{"__builtin_compare_and_swap", KW___BUILTIN_COMPARE_AND_SWAP},
|
||||
#line 101 "kw.gperf"
|
||||
{"__builtin_strpbrk", KW___BUILTIN_STRPBRK},
|
||||
#line 41 "kw.gperf"
|
||||
{"asm", KW_ASM},
|
||||
#line 55 "kw.gperf"
|
||||
{"line", KW_LINE},
|
||||
#line 86 "kw.gperf"
|
||||
{"__builtin_constant_p", KW___BUILTIN_CONSTANT_P},
|
||||
#line 74 "kw.gperf"
|
||||
{"__alignof__", KW___ALIGNOF__},
|
||||
#line 60 "kw.gperf"
|
||||
{"strpbrk", KW_STRPBRK},
|
||||
{""},
|
||||
#line 47 "kw.gperf"
|
||||
{"elif", KW_ELIF},
|
||||
{""}, {""},
|
||||
#line 103 "kw.gperf"
|
||||
{"__builtin_sub_overflow", KW___BUILTIN_SUB_OVERFLOW},
|
||||
#line 72 "kw.gperf"
|
||||
{"_Thread_local", KW__THREAD_LOCAL},
|
||||
#line 96 "kw.gperf"
|
||||
{"__builtin_popcountl", KW___BUILTIN_POPCOUNTL},
|
||||
#line 97 "kw.gperf"
|
||||
{"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL},
|
||||
#line 108 "kw.gperf"
|
||||
{"}", KW_RB},
|
||||
#line 92 "kw.gperf"
|
||||
{"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW},
|
||||
#line 104 "kw.gperf"
|
||||
{"__builtin_types_compatible_p", KW___BUILTIN_TYPES_COMPATIBLE_P},
|
||||
{""},
|
||||
#line 30 "kw.gperf"
|
||||
{"float", KW_FLOAT},
|
||||
#line 87 "kw.gperf"
|
||||
{"__builtin_expect", KW___BUILTIN_EXPECT},
|
||||
#line 82 "kw.gperf"
|
||||
{"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW},
|
||||
#line 20 "kw.gperf"
|
||||
{"for", KW_FOR},
|
||||
{""},
|
||||
#line 91 "kw.gperf"
|
||||
{"__builtin_fpclassify", KW___BUILTIN_FPCLASSIFY},
|
||||
#line 107 "kw.gperf"
|
||||
{"{", KW_LB},
|
||||
#line 42 "kw.gperf"
|
||||
{"default", KW_DEFAULT},
|
||||
{""},
|
||||
#line 89 "kw.gperf"
|
||||
{"__builtin_ffsl", KW___BUILTIN_FFSL},
|
||||
#line 90 "kw.gperf"
|
||||
{"__builtin_ffsll", KW___BUILTIN_FFSLL},
|
||||
#line 56 "kw.gperf"
|
||||
{"pragma", KW_PRAGMA},
|
||||
#line 119 "kw.gperf"
|
||||
{"->", KW_ARROW},
|
||||
{""},
|
||||
#line 18 "kw.gperf"
|
||||
{"char", KW_CHAR},
|
||||
#line 64 "kw.gperf"
|
||||
{"undef", KW_UNDEF},
|
||||
#line 61 "kw.gperf"
|
||||
{"strstr", KW_STRSTR},
|
||||
{""},
|
||||
#line 67 "kw.gperf"
|
||||
{"_Alignof", KW__ALIGNOF},
|
||||
{""},
|
||||
#line 49 "kw.gperf"
|
||||
{"error", KW_ERROR},
|
||||
#line 58 "kw.gperf"
|
||||
{"strchr", KW_STRCHR},
|
||||
#line 40 "kw.gperf"
|
||||
{"defined", KW_DEFINED},
|
||||
#line 65 "kw.gperf"
|
||||
{"volatile", KW_VOLATILE},
|
||||
#line 71 "kw.gperf"
|
||||
{"_Static_assert", KW__STATIC_ASSERT},
|
||||
#line 48 "kw.gperf"
|
||||
{"endif", KW_ENDIF},
|
||||
#line 16 "kw.gperf"
|
||||
{"static", KW_STATIC},
|
||||
{""},
|
||||
#line 66 "kw.gperf"
|
||||
{"_Alignas", KW__ALIGNAS},
|
||||
{""},
|
||||
#line 84 "kw.gperf"
|
||||
{"__builtin_atomic_exchange", KW___BUILTIN_ATOMIC_EXCHANGE},
|
||||
#line 39 "kw.gperf"
|
||||
{"define", KW_DEFINE},
|
||||
{""},
|
||||
#line 35 "kw.gperf"
|
||||
{"continue", KW_CONTINUE},
|
||||
#line 24 "kw.gperf"
|
||||
{"long", KW_LONG},
|
||||
{""},
|
||||
#line 99 "kw.gperf"
|
||||
{"__builtin_strchr", KW___BUILTIN_STRCHR},
|
||||
#line 12 "kw.gperf"
|
||||
{"if", KW_IF},
|
||||
#line 54 "kw.gperf"
|
||||
{"int", KW_INT},
|
||||
{""},
|
||||
#line 37 "kw.gperf"
|
||||
{"ifdef", KW_IFDEF},
|
||||
{""}, {""}, {""},
|
||||
#line 98 "kw.gperf"
|
||||
{"__builtin_reg_class", KW___BUILTIN_REG_CLASS},
|
||||
{""},
|
||||
#line 102 "kw.gperf"
|
||||
{"__builtin_strstr", KW___BUILTIN_STRSTR},
|
||||
{""},
|
||||
#line 45 "kw.gperf"
|
||||
{"__attribute__", KW___ATTRIBUTE__},
|
||||
{""},
|
||||
#line 33 "kw.gperf"
|
||||
{"break", KW_BREAK},
|
||||
#line 50 "kw.gperf"
|
||||
{"extern", KW_EXTERN},
|
||||
{""},
|
||||
#line 80 "kw.gperf"
|
||||
{"__thread", KW__THREAD_LOCAL},
|
||||
#line 46 "kw.gperf"
|
||||
{"_Noreturn", KW__NORETURN},
|
||||
{""},
|
||||
#line 38 "kw.gperf"
|
||||
{"ifndef", KW_IFNDEF},
|
||||
#line 21 "kw.gperf"
|
||||
{"do", KW_DO},
|
||||
{""}, {""}, {""},
|
||||
#line 59 "kw.gperf"
|
||||
{"strlen", KW_STRLEN},
|
||||
#line 52 "kw.gperf"
|
||||
{"include_next", KW_INCLUDE_NEXT},
|
||||
#line 70 "kw.gperf"
|
||||
{"_Generic", KW__GENERIC},
|
||||
#line 34 "kw.gperf"
|
||||
{"enum", KW_ENUM},
|
||||
{""},
|
||||
#line 27 "kw.gperf"
|
||||
{"switch", KW_SWITCH},
|
||||
#line 93 "kw.gperf"
|
||||
{"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW},
|
||||
#line 77 "kw.gperf"
|
||||
{"__int128", KW___INT128},
|
||||
#line 83 "kw.gperf"
|
||||
{"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED},
|
||||
{""},
|
||||
#line 32 "kw.gperf"
|
||||
{"signed", KW_SIGNED},
|
||||
#line 36 "kw.gperf"
|
||||
{"include", KW_INCLUDE},
|
||||
#line 57 "kw.gperf"
|
||||
{"restrict", KW_RESTRICT},
|
||||
#line 43 "kw.gperf"
|
||||
{"auto", KW_AUTO},
|
||||
{""},
|
||||
#line 111 "kw.gperf"
|
||||
{"&", KW_AMP},
|
||||
#line 117 "kw.gperf"
|
||||
{"&&", KW_LOGAND},
|
||||
#line 76 "kw.gperf"
|
||||
{"__inline", KW_INLINE},
|
||||
#line 51 "kw.gperf"
|
||||
{"goto", KW_GOTO},
|
||||
{""}, {""}, {""},
|
||||
#line 23 "kw.gperf"
|
||||
{"unsigned", KW_UNSIGNED},
|
||||
{""}, {""},
|
||||
#line 100 "kw.gperf"
|
||||
{"__builtin_strlen", KW___BUILTIN_STRLEN},
|
||||
{""},
|
||||
#line 94 "kw.gperf"
|
||||
{"__builtin_offsetof", KW___BUILTIN_OFFSETOF},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 14 "kw.gperf"
|
||||
{"return", KW_RETURN},
|
||||
{""}, {""}, {""},
|
||||
#line 26 "kw.gperf"
|
||||
{"union", KW_UNION},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
#line 120 "kw.gperf"
|
||||
{".", KW_DOT},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 53 "kw.gperf"
|
||||
{"inline", KW_INLINE},
|
||||
{""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 44 "kw.gperf"
|
||||
{"register", KW_REGISTER},
|
||||
{""}, {""},
|
||||
#line 112 "kw.gperf"
|
||||
{"*", KW_STAR},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 106 "kw.gperf"
|
||||
{")", KW_RP},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 105 "kw.gperf"
|
||||
{"(", KW_LP},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 113 "kw.gperf"
|
||||
{"!", KW_EXCLAIM}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
register unsigned int key = hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE)
|
||||
{
|
||||
register const char *s = wordlist[key].name;
|
||||
|
||||
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
|
||||
return &wordlist[key];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
414
third_party/chibicc/parse.c
vendored
414
third_party/chibicc/parse.c
vendored
|
@ -16,9 +16,14 @@
|
|||
// So it is very easy to lookahead arbitrary number of tokens in this
|
||||
// parser.
|
||||
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/ffs.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
#include "third_party/chibicc/kw.h"
|
||||
|
||||
typedef struct InitDesg InitDesg;
|
||||
typedef struct Initializer Initializer;
|
||||
|
@ -217,22 +222,31 @@ static Node *new_num(int64_t val, Token *tok) {
|
|||
return node;
|
||||
}
|
||||
|
||||
static Node *new_int(int64_t val, Token *tok) {
|
||||
Node *node = new_num(val, tok);
|
||||
node->ty = ty_int;
|
||||
return node;
|
||||
}
|
||||
|
||||
static Node *new_bool(int64_t val, Token *tok) {
|
||||
Node *node = new_num(val, tok);
|
||||
node->ty = ty_bool;
|
||||
return node;
|
||||
}
|
||||
|
||||
static Node *new_long(int64_t val, Token *tok) {
|
||||
Node *node = new_node(ND_NUM, tok);
|
||||
node->val = val;
|
||||
Node *node = new_num(val, tok);
|
||||
node->ty = ty_long;
|
||||
return node;
|
||||
}
|
||||
|
||||
static Node *new_ulong(long val, Token *tok) {
|
||||
Node *node = new_node(ND_NUM, tok);
|
||||
node->val = val;
|
||||
static Node *new_ulong(int64_t val, Token *tok) {
|
||||
Node *node = new_num(val, tok);
|
||||
node->ty = ty_ulong;
|
||||
return node;
|
||||
}
|
||||
|
||||
static Node *new_var_node(Obj *var, Token *tok) {
|
||||
if (!var) DebugBreak();
|
||||
CHECK_NOTNULL(var);
|
||||
Node *node = new_node(ND_VAR, tok);
|
||||
node->var = var;
|
||||
|
@ -605,8 +619,6 @@ static Token *thing_attributes(Token *tok, void *arg) {
|
|||
error_tok(tok, "unknown function attribute");
|
||||
}
|
||||
|
||||
Token *to;
|
||||
|
||||
// declspec = ("void" | "_Bool" | "char" | "short" | "int" | "long"
|
||||
// | "typedef" | "static" | "extern" | "inline"
|
||||
// | "_Thread_local" | "__thread"
|
||||
|
@ -646,25 +658,26 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
UNSIGNED = 1 << 18,
|
||||
INT128 = 1 << 19,
|
||||
};
|
||||
unsigned char kw;
|
||||
Type *ty = copy_type(ty_int);
|
||||
int counter = 0;
|
||||
bool is_const = false;
|
||||
bool is_atomic = false;
|
||||
while (is_typename(tok)) {
|
||||
if ((kw = GetKw(tok->loc, tok->len))) {
|
||||
// Handle storage class specifiers.
|
||||
if (EQUAL(tok, "typedef") || EQUAL(tok, "static") || EQUAL(tok, "extern") ||
|
||||
EQUAL(tok, "inline") || EQUAL(tok, "__inline") ||
|
||||
EQUAL(tok, "_Thread_local") || EQUAL(tok, "__thread")) {
|
||||
if (kw == KW_TYPEDEF || kw == KW_STATIC || kw == KW_EXTERN ||
|
||||
kw == KW_INLINE || kw == KW__THREAD_LOCAL) {
|
||||
if (!attr)
|
||||
error_tok(tok,
|
||||
"storage class specifier is not allowed in this context");
|
||||
if (EQUAL(tok, "typedef")) {
|
||||
if (kw == KW_TYPEDEF) {
|
||||
attr->is_typedef = true;
|
||||
} else if (EQUAL(tok, "static")) {
|
||||
} else if (kw == KW_STATIC) {
|
||||
attr->is_static = true;
|
||||
} else if (EQUAL(tok, "extern")) {
|
||||
} else if (kw == KW_EXTERN) {
|
||||
attr->is_extern = true;
|
||||
} else if (EQUAL(tok, "inline") || EQUAL(tok, "__inline")) {
|
||||
} else if (kw == KW_INLINE) {
|
||||
attr->is_inline = true;
|
||||
} else {
|
||||
attr->is_tls = true;
|
||||
|
@ -672,29 +685,29 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
if (attr->is_typedef &&
|
||||
attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls >
|
||||
1) {
|
||||
to = tok;
|
||||
error_tok(tok, "typedef may not be used together with static,"
|
||||
" extern, inline, __thread or _Thread_local");
|
||||
}
|
||||
tok = tok->next;
|
||||
goto Continue;
|
||||
}
|
||||
if (CONSUME(&tok, tok, "_Noreturn")) {
|
||||
if (kw == KW__NORETURN) {
|
||||
if (attr) attr->is_noreturn = true;
|
||||
tok = tok->next;
|
||||
goto Continue;
|
||||
}
|
||||
if (CONSUME(&tok, tok, "const")) {
|
||||
if (kw == KW_CONST) {
|
||||
is_const = true;
|
||||
tok = tok->next;
|
||||
goto Continue;
|
||||
}
|
||||
// These keywords are recognized but ignored.
|
||||
if (CONSUME(&tok, tok, "volatile") || CONSUME(&tok, tok, "auto") ||
|
||||
CONSUME(&tok, tok, "register") || CONSUME(&tok, tok, "restrict") ||
|
||||
CONSUME(&tok, tok, "__restrict") ||
|
||||
CONSUME(&tok, tok, "__restrict__")) {
|
||||
if (kw == KW_VOLATILE || kw == KW_AUTO || kw == KW_REGISTER ||
|
||||
kw == KW_RESTRICT) {
|
||||
tok = tok->next;
|
||||
goto Continue;
|
||||
}
|
||||
if (EQUAL(tok, "_Atomic")) {
|
||||
if (kw == KW__ATOMIC) {
|
||||
tok = tok->next;
|
||||
if (EQUAL(tok, "(")) {
|
||||
ty = typename(&tok, tok->next);
|
||||
|
@ -703,7 +716,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
is_atomic = true;
|
||||
goto Continue;
|
||||
}
|
||||
if (EQUAL(tok, "_Alignas")) {
|
||||
if (kw == KW__ALIGNAS) {
|
||||
if (!attr) error_tok(tok, "_Alignas is not allowed in this context");
|
||||
tok = skip(tok->next, '(');
|
||||
if (is_typename(tok)) {
|
||||
|
@ -718,18 +731,19 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
tok = skip(tok, ')');
|
||||
goto Continue;
|
||||
}
|
||||
}
|
||||
// Handle user-defined types.
|
||||
Type *ty2 = find_typedef(tok);
|
||||
if (EQUAL(tok, "struct") || EQUAL(tok, "union") || EQUAL(tok, "enum") ||
|
||||
EQUAL(tok, "typeof") || EQUAL(tok, "__typeof") || ty2) {
|
||||
if (ty2 || kw == KW_STRUCT || kw == KW_UNION || kw == KW_ENUM ||
|
||||
kw == KW_TYPEOF) {
|
||||
if (counter) break;
|
||||
if (EQUAL(tok, "struct")) {
|
||||
if (kw == KW_STRUCT) {
|
||||
ty = struct_decl(&tok, tok->next);
|
||||
} else if (EQUAL(tok, "union")) {
|
||||
} else if (kw == KW_UNION) {
|
||||
ty = union_decl(&tok, tok->next);
|
||||
} else if (EQUAL(tok, "enum")) {
|
||||
} else if (kw == KW_ENUM) {
|
||||
ty = enum_specifier(&tok, tok->next);
|
||||
} else if (EQUAL(tok, "typeof") || EQUAL(tok, "__typeof")) {
|
||||
} else if (kw == KW_TYPEOF) {
|
||||
ty = typeof_specifier(&tok, tok->next);
|
||||
} else {
|
||||
ty = ty2;
|
||||
|
@ -739,30 +753,31 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
goto Continue;
|
||||
}
|
||||
// Handle built-in types.
|
||||
if (EQUAL(tok, "void"))
|
||||
if (kw == KW_VOID) {
|
||||
counter += VOID;
|
||||
else if (EQUAL(tok, "_Bool"))
|
||||
} else if (kw == KW__BOOL) {
|
||||
counter += BOOL;
|
||||
else if (EQUAL(tok, "char"))
|
||||
} else if (kw == KW_CHAR) {
|
||||
counter += CHAR;
|
||||
else if (EQUAL(tok, "short"))
|
||||
} else if (kw == KW_SHORT) {
|
||||
counter += SHORT;
|
||||
else if (EQUAL(tok, "int"))
|
||||
} else if (kw == KW_INT) {
|
||||
counter += INT;
|
||||
else if (EQUAL(tok, "long"))
|
||||
} else if (kw == KW_LONG) {
|
||||
counter += LONG;
|
||||
else if (EQUAL(tok, "__int128"))
|
||||
} else if (kw == KW___INT128) {
|
||||
counter += INT128;
|
||||
else if (EQUAL(tok, "float"))
|
||||
} else if (kw == KW_FLOAT) {
|
||||
counter += FLOAT;
|
||||
else if (EQUAL(tok, "double"))
|
||||
} else if (kw == KW_DOUBLE) {
|
||||
counter += DOUBLE;
|
||||
else if (EQUAL(tok, "signed"))
|
||||
} else if (kw == KW_SIGNED) {
|
||||
counter |= SIGNED;
|
||||
else if (EQUAL(tok, "unsigned"))
|
||||
} else if (kw == KW_UNSIGNED) {
|
||||
counter |= UNSIGNED;
|
||||
else
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
switch (counter) {
|
||||
case VOID:
|
||||
ty = copy_type(ty_void);
|
||||
|
@ -843,10 +858,10 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
ty = copy_type(ty);
|
||||
ty->is_atomic = true;
|
||||
}
|
||||
/* if (attr && is_const) { */
|
||||
/* ty = copy_type(ty); */
|
||||
/* ty->is_const = true; */
|
||||
/* } */
|
||||
if (is_const) {
|
||||
ty = copy_type(ty);
|
||||
ty->is_const = true;
|
||||
}
|
||||
*rest = tok;
|
||||
return ty;
|
||||
}
|
||||
|
@ -895,10 +910,15 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
|
|||
new_lvar(strndup(name->loc, name->len), ty2);
|
||||
}
|
||||
if (ty2->kind == TY_ARRAY) {
|
||||
// "array of T" is converted to "pointer to T" only in the parameter
|
||||
// context. For example, *argv[] is converted to **argv by this.
|
||||
ty2 = pointer_to(ty2->base);
|
||||
ty2->name = name;
|
||||
// "array of T" decays to "pointer to T" only in the parameter
|
||||
// context. For example, *argv[] is converted to **argv here.
|
||||
Type *ty3 = ty2;
|
||||
ty3 = pointer_to(ty2->base);
|
||||
ty3->name = name;
|
||||
ty3->array_len = ty2->array_len;
|
||||
ty3->is_static = ty2->is_static;
|
||||
ty3->is_restrict = ty2->is_restrict;
|
||||
ty2 = ty3;
|
||||
} else if (ty2->kind == TY_FUNC) {
|
||||
// Likewise, a function is converted to a pointer to a function
|
||||
// only in the parameter context.
|
||||
|
@ -918,16 +938,32 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
|
|||
|
||||
// array-dimensions = ("static" | "restrict")* const-expr? "]" type-suffix
|
||||
static Type *array_dimensions(Token **rest, Token *tok, Type *ty) {
|
||||
while (EQUAL(tok, "static") || EQUAL(tok, "restrict")) tok = tok->next;
|
||||
Node *expr;
|
||||
bool is_static, is_restrict;
|
||||
is_static = false;
|
||||
is_restrict = false;
|
||||
for (;; tok = tok->next) {
|
||||
if (EQUAL(tok, "static")) {
|
||||
is_static = true;
|
||||
} else if (EQUAL(tok, "restrict")) {
|
||||
is_restrict = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (EQUAL(tok, "]")) {
|
||||
ty = type_suffix(rest, tok->next, ty);
|
||||
return array_of(ty, -1);
|
||||
}
|
||||
Node *expr = conditional(&tok, tok);
|
||||
ty = array_of(ty, -1);
|
||||
} else {
|
||||
expr = conditional(&tok, tok);
|
||||
tok = skip(tok, ']');
|
||||
ty = type_suffix(rest, tok, ty);
|
||||
if (ty->kind == TY_VLA || !is_const_expr(expr)) return vla_of(ty, expr);
|
||||
return array_of(ty, eval(expr));
|
||||
ty = array_of(ty, eval(expr));
|
||||
}
|
||||
ty->is_static = is_static;
|
||||
ty->is_restrict = is_restrict;
|
||||
return ty;
|
||||
}
|
||||
|
||||
// type-suffix = "(" func-params
|
||||
|
@ -944,10 +980,21 @@ static Type *type_suffix(Token **rest, Token *tok, Type *ty) {
|
|||
static Type *pointers(Token **rest, Token *tok, Type *ty) {
|
||||
while (CONSUME(&tok, tok, "*")) {
|
||||
ty = pointer_to(ty);
|
||||
while (EQUAL(tok, "const") || EQUAL(tok, "volatile") ||
|
||||
EQUAL(tok, "restrict") || EQUAL(tok, "__restrict") ||
|
||||
EQUAL(tok, "__restrict__"))
|
||||
for (;;) {
|
||||
if (EQUAL(tok, "const")) {
|
||||
ty->is_const = true;
|
||||
tok = tok->next;
|
||||
} else if (EQUAL(tok, "volatile")) {
|
||||
ty->is_volatile = true;
|
||||
tok = tok->next;
|
||||
} else if (EQUAL(tok, "restrict") || EQUAL(tok, "__restrict") ||
|
||||
EQUAL(tok, "__restrict__")) {
|
||||
ty->is_restrict = true;
|
||||
tok = tok->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return ty;
|
||||
|
@ -1668,22 +1715,9 @@ static void gvar_initializer(Token **rest, Token *tok, Obj *var) {
|
|||
|
||||
// Returns true if a given token represents a type.
|
||||
static bool is_typename(Token *tok) {
|
||||
static HashMap map;
|
||||
if (map.capacity == 0) {
|
||||
static char *kw[] = {
|
||||
"void", "_Bool", "char", "short", "int",
|
||||
"long", "struct", "union", "typedef", "enum",
|
||||
"static", "extern", "_Alignas", "signed", "unsigned",
|
||||
"const", "volatile", "auto", "register", "restrict",
|
||||
"__restrict", "__restrict__", "_Noreturn", "float", "double",
|
||||
"typeof", "__typeof", "inline", "__inline", "_Thread_local",
|
||||
"__thread", "_Atomic", "__int128",
|
||||
};
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
|
||||
hashmap_put(&map, kw[i], (void *)1);
|
||||
}
|
||||
}
|
||||
return hashmap_get2(&map, tok->loc, tok->len) || find_typedef(tok);
|
||||
unsigned char kw;
|
||||
kw = GetKw(tok->loc, tok->len);
|
||||
return (kw && !(kw & -32)) || find_typedef(tok);
|
||||
}
|
||||
|
||||
static bool is_const_expr_true(Node *node) {
|
||||
|
@ -2286,28 +2320,46 @@ static Node *to_assign(Node *binary) {
|
|||
// | "<<=" | ">>="
|
||||
static Node *assign(Token **rest, Token *tok) {
|
||||
Node *node = conditional(&tok, tok);
|
||||
if (EQUAL(tok, "="))
|
||||
if (tok->len == 1) {
|
||||
if (tok->loc[0] == '=') {
|
||||
return new_binary(ND_ASSIGN, node, assign(rest, tok->next), tok);
|
||||
if (EQUAL(tok, "+="))
|
||||
}
|
||||
} else if (tok->len == 2) {
|
||||
if (tok->loc[0] == '+' && tok->loc[1] == '=') {
|
||||
return to_assign(new_add(node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "-="))
|
||||
}
|
||||
if (tok->loc[0] == '-' && tok->loc[1] == '=') {
|
||||
return to_assign(new_sub(node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "*="))
|
||||
}
|
||||
if (tok->loc[0] == '*' && tok->loc[1] == '=') {
|
||||
return to_assign(new_binary(ND_MUL, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "/="))
|
||||
}
|
||||
if (tok->loc[0] == '/' && tok->loc[1] == '=') {
|
||||
return to_assign(new_binary(ND_DIV, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "%="))
|
||||
}
|
||||
if (tok->loc[0] == '%' && tok->loc[1] == '=') {
|
||||
return to_assign(new_binary(ND_REM, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "&="))
|
||||
return to_assign(new_binary(ND_BINAND, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "|="))
|
||||
return to_assign(new_binary(ND_BINOR, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "^="))
|
||||
return to_assign(new_binary(ND_BINXOR, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, "<<="))
|
||||
}
|
||||
if (tok->loc[0] == '&' && tok->loc[1] == '=') {
|
||||
return to_assign(
|
||||
new_binary(ND_BINAND, node, assign(rest, tok->next), tok));
|
||||
}
|
||||
if (tok->loc[0] == '|' && tok->loc[1] == '=') {
|
||||
return to_assign(
|
||||
new_binary(ND_BINOR, node, assign(rest, tok->next), tok));
|
||||
}
|
||||
if (tok->loc[0] == '^' && tok->loc[1] == '=') {
|
||||
return to_assign(
|
||||
new_binary(ND_BINXOR, node, assign(rest, tok->next), tok));
|
||||
}
|
||||
} else if (tok->len == 3) {
|
||||
if (tok->loc[0] == '<' && tok->loc[1] == '<' && tok->loc[2] == '=') {
|
||||
return to_assign(new_binary(ND_SHL, node, assign(rest, tok->next), tok));
|
||||
if (EQUAL(tok, ">>="))
|
||||
}
|
||||
if (tok->loc[0] == '>' && tok->loc[1] == '>' && tok->loc[2] == '=') {
|
||||
return to_assign(new_binary(ND_SHR, node, assign(rest, tok->next), tok));
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
}
|
||||
|
@ -2447,17 +2499,20 @@ static Node *relational(Token **rest, Token *tok) {
|
|||
node = new_binary(ND_LT, node, shift(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "<=")) {
|
||||
if (tok->len == 2) {
|
||||
if (tok->loc[0] == '<' && tok->loc[1] == '=') {
|
||||
node = new_binary(ND_LE, node, shift(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, ">")) {
|
||||
if (tok->loc[0] == '>' && tok->loc[1] == '=') {
|
||||
node = new_binary(ND_LE, shift(&tok, tok->next), node, start);
|
||||
continue;
|
||||
}
|
||||
} else if (tok->len == 1) {
|
||||
if (tok->loc[0] == '>') {
|
||||
node = new_binary(ND_LT, shift(&tok, tok->next), node, start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, ">=")) {
|
||||
node = new_binary(ND_LE, shift(&tok, tok->next), node, start);
|
||||
continue;
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
|
@ -2469,14 +2524,16 @@ static Node *shift(Token **rest, Token *tok) {
|
|||
Node *node = add(&tok, tok);
|
||||
for (;;) {
|
||||
Token *start = tok;
|
||||
if (EQUAL(tok, "<<")) {
|
||||
if (tok->len == 2) {
|
||||
if (tok->loc[0] == '<' && tok->loc[1] == '<') {
|
||||
node = new_binary(ND_SHL, node, add(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, ">>")) {
|
||||
if (tok->loc[0] == '>' && tok->loc[1] == '>') {
|
||||
node = new_binary(ND_SHR, node, add(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
}
|
||||
|
@ -2582,14 +2639,16 @@ static Node *add(Token **rest, Token *tok) {
|
|||
Node *node = mul(&tok, tok);
|
||||
for (;;) {
|
||||
Token *start = tok;
|
||||
if (EQUAL(tok, "+")) {
|
||||
if (tok->len == 1) {
|
||||
if (tok->loc[0] == '+') {
|
||||
node = new_add(node, mul(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "-")) {
|
||||
if (tok->loc[0] == '-') {
|
||||
node = new_sub(node, mul(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
}
|
||||
|
@ -2600,18 +2659,20 @@ static Node *mul(Token **rest, Token *tok) {
|
|||
Node *node = cast(&tok, tok);
|
||||
for (;;) {
|
||||
Token *start = tok;
|
||||
if (EQUAL(tok, "*")) {
|
||||
if (tok->len == 1) {
|
||||
if (tok->loc[0] == '*') {
|
||||
node = new_mul(node, cast(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "/")) {
|
||||
if (tok->loc[0] == '/') {
|
||||
node = new_binary(ND_DIV, node, cast(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "%")) {
|
||||
if (tok->loc[0] == '%') {
|
||||
node = new_binary(ND_REM, node, cast(&tok, tok->next), start);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
}
|
||||
|
@ -2638,9 +2699,14 @@ static Node *cast(Token **rest, Token *tok) {
|
|||
// | "&&" ident
|
||||
// | postfix
|
||||
static Node *unary(Token **rest, Token *tok) {
|
||||
if (EQUAL(tok, "+")) return cast(rest, tok->next);
|
||||
if (EQUAL(tok, "-")) return new_unary(ND_NEG, cast(rest, tok->next), tok);
|
||||
if (EQUAL(tok, "&")) {
|
||||
if (tok->len == 1) {
|
||||
if (tok->loc[0] == '+') {
|
||||
return cast(rest, tok->next);
|
||||
}
|
||||
if (tok->loc[0] == '-') {
|
||||
return new_unary(ND_NEG, cast(rest, tok->next), tok);
|
||||
}
|
||||
if (tok->loc[0] == '&') {
|
||||
Node *lhs = cast(rest, tok->next);
|
||||
add_type(lhs);
|
||||
if (lhs->kind == ND_MEMBER && lhs->member->is_bitfield) {
|
||||
|
@ -2648,7 +2714,7 @@ static Node *unary(Token **rest, Token *tok) {
|
|||
}
|
||||
return new_unary(ND_ADDR, lhs, tok);
|
||||
}
|
||||
if (EQUAL(tok, "*")) {
|
||||
if (tok->loc[0] == '*') {
|
||||
// [https://www.sigbus.info/n1570#6.5.3.2p4] This is an oddity
|
||||
// in the C spec, but dereferencing a function shouldn't do
|
||||
// anything. If foo is a function, `*foo`, `**foo` or `*****foo`
|
||||
|
@ -2658,16 +2724,23 @@ static Node *unary(Token **rest, Token *tok) {
|
|||
if (node->ty->kind == TY_FUNC) return node;
|
||||
return new_unary(ND_DEREF, node, tok);
|
||||
}
|
||||
if (EQUAL(tok, "!")) return new_unary(ND_NOT, cast(rest, tok->next), tok);
|
||||
if (EQUAL(tok, "~")) return new_unary(ND_BITNOT, cast(rest, tok->next), tok);
|
||||
if (tok->loc[0] == '!') {
|
||||
return new_unary(ND_NOT, cast(rest, tok->next), tok);
|
||||
}
|
||||
if (tok->loc[0] == '~') {
|
||||
return new_unary(ND_BITNOT, cast(rest, tok->next), tok);
|
||||
}
|
||||
} else if (tok->len == 2) {
|
||||
// Read ++i as i+=1
|
||||
if (EQUAL(tok, "++"))
|
||||
if (tok->loc[0] == '+' && tok->loc[1] == '+') {
|
||||
return to_assign(new_add(unary(rest, tok->next), new_num(1, tok), tok));
|
||||
}
|
||||
// Read --i as i-=1
|
||||
if (EQUAL(tok, "--"))
|
||||
if (tok->loc[0] == '-' && tok->loc[1] == '-') {
|
||||
return to_assign(new_sub(unary(rest, tok->next), new_num(1, tok), tok));
|
||||
}
|
||||
// [GNU] labels-as-values
|
||||
if (EQUAL(tok, "&&")) {
|
||||
if (tok->loc[0] == '&' && tok->loc[1] == '&') {
|
||||
Node *node = new_node(ND_LABEL_VAL, tok);
|
||||
node->label = get_ident(tok->next);
|
||||
node->goto_next = gotos;
|
||||
|
@ -2675,10 +2748,11 @@ static Node *unary(Token **rest, Token *tok) {
|
|||
*rest = tok->next->next;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return postfix(rest, tok);
|
||||
}
|
||||
|
||||
// struct-members = (declspec declarator ("," declarator)* ";")*
|
||||
// struct-members = (declspec declarator ("," declarator)* ";" javadown?)*
|
||||
static void struct_members(Token **rest, Token *tok, Type *ty) {
|
||||
Member head = {};
|
||||
Member *cur = &head;
|
||||
|
@ -2712,6 +2786,9 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
}
|
||||
cur = cur->next = mem;
|
||||
}
|
||||
if (tok->kind == TK_JAVADOWN) {
|
||||
tok = tok->next;
|
||||
}
|
||||
}
|
||||
// If the last element is an array of incomplete type, it's
|
||||
// called a "flexible array member". It should behave as if
|
||||
|
@ -2904,11 +2981,12 @@ static Node *postfix(Token **rest, Token *tok) {
|
|||
}
|
||||
Node *node = primary(&tok, tok);
|
||||
for (;;) {
|
||||
if (EQUAL(tok, "(")) {
|
||||
if (tok->len == 1) {
|
||||
if (tok->loc[0] == '(') {
|
||||
node = funcall(&tok, tok->next, node);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "[")) {
|
||||
if (tok->loc[0] == '[') {
|
||||
// x[y] is short for *(x+y)
|
||||
Token *start = tok;
|
||||
Node *idx = expr(&tok, tok->next);
|
||||
|
@ -2916,28 +2994,30 @@ static Node *postfix(Token **rest, Token *tok) {
|
|||
node = new_unary(ND_DEREF, new_add(node, idx, start), start);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, ".")) {
|
||||
if (tok->loc[0] == '.') {
|
||||
node = struct_ref(node, tok->next);
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "->")) {
|
||||
} else if (tok->len == 2) {
|
||||
if (tok->loc[0] == '-' && tok->loc[1] == '>') {
|
||||
// x->y is short for (*x).y
|
||||
node = new_unary(ND_DEREF, node, tok);
|
||||
node = struct_ref(node, tok->next);
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "++")) {
|
||||
if (tok->loc[0] == '+' && tok->loc[1] == '+') {
|
||||
node = new_inc_dec(node, tok, 1);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "--")) {
|
||||
if (tok->loc[0] == '-' && tok->loc[1] == '-') {
|
||||
node = new_inc_dec(node, tok, -1);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*rest = tok;
|
||||
return node;
|
||||
}
|
||||
|
@ -3033,20 +3113,23 @@ static Node *generic_selection(Token **rest, Token *tok) {
|
|||
// | str
|
||||
// | num
|
||||
static Node *primary(Token **rest, Token *tok) {
|
||||
Token *start = tok;
|
||||
if (EQUAL(tok, "(") && EQUAL(tok->next, "{")) {
|
||||
Token *start;
|
||||
unsigned char kw;
|
||||
start = tok;
|
||||
if ((kw = GetKw(tok->loc, tok->len))) {
|
||||
if (kw == KW_LP && EQUAL(tok->next, "{")) {
|
||||
// This is a GNU statement expresssion.
|
||||
Node *node = new_node(ND_STMT_EXPR, tok);
|
||||
node->body = compound_stmt(&tok, tok->next->next)->body;
|
||||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "(")) {
|
||||
if (kw == KW_LP) {
|
||||
Node *node = expr(&tok, tok->next);
|
||||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "sizeof") && EQUAL(tok->next, "(") &&
|
||||
if (kw == KW_SIZEOF && EQUAL(tok->next, "(") &&
|
||||
is_typename(tok->next->next)) {
|
||||
Type *ty = typename(&tok, tok->next->next);
|
||||
*rest = skip(tok, ')');
|
||||
|
@ -3060,7 +3143,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
}
|
||||
return new_ulong(ty->size, start);
|
||||
}
|
||||
if (EQUAL(tok, "sizeof")) {
|
||||
if (kw == KW_SIZEOF) {
|
||||
Node *node = unary(rest, tok->next);
|
||||
add_type(node);
|
||||
if (node->ty->kind == TY_VLA) {
|
||||
|
@ -3068,36 +3151,35 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
}
|
||||
return new_ulong(node->ty->size, tok);
|
||||
}
|
||||
if ((EQUAL(tok, "_Alignof") || EQUAL(tok, "__alignof__")) &&
|
||||
EQUAL(tok->next, "(") && is_typename(tok->next->next)) {
|
||||
if ((kw == KW__ALIGNOF || kw == KW___ALIGNOF__) && EQUAL(tok->next, "(") &&
|
||||
is_typename(tok->next->next)) {
|
||||
Type *ty = typename(&tok, tok->next->next);
|
||||
*rest = skip(tok, ')');
|
||||
return new_ulong(ty->align, tok);
|
||||
}
|
||||
if (EQUAL(tok, "_Alignof") || EQUAL(tok, "__alignof__")) {
|
||||
if ((kw == KW__ALIGNOF || kw == KW___ALIGNOF__)) {
|
||||
Node *node = unary(rest, tok->next);
|
||||
add_type(node);
|
||||
return new_ulong(node->ty->align, tok);
|
||||
}
|
||||
if (EQUAL(tok, "_Generic")) {
|
||||
if (kw == KW__GENERIC) {
|
||||
return generic_selection(rest, tok->next);
|
||||
}
|
||||
if (tok->len > 10 && !memcmp(tok->loc, "__builtin_", 10)) {
|
||||
if (EQUAL(tok, "__builtin_constant_p")) {
|
||||
if (kw == KW___BUILTIN_CONSTANT_P) {
|
||||
tok = skip(tok->next, '(');
|
||||
Node *e = expr(&tok, tok);
|
||||
Node *e = assign(&tok, tok);
|
||||
*rest = skip(tok, ')');
|
||||
return new_num(is_const_expr(e), start); /* DCE */
|
||||
return new_bool(is_const_expr(e), start); /* DCE */
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_types_compatible_p")) {
|
||||
if (kw == KW___BUILTIN_TYPES_COMPATIBLE_P) {
|
||||
tok = skip(tok->next, '(');
|
||||
Type *t1 = typename(&tok, tok);
|
||||
tok = skip(tok, ',');
|
||||
Type *t2 = typename(&tok, tok);
|
||||
*rest = skip(tok, ')');
|
||||
return new_num(is_compatible(t1, t2), start);
|
||||
return new_bool(is_compatible(t1, t2), start);
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_offsetof")) {
|
||||
if (kw == KW___BUILTIN_OFFSETOF) {
|
||||
tok = skip(tok->next, '(');
|
||||
Token *stok = tok;
|
||||
Type *tstruct = typename(&tok, tok);
|
||||
|
@ -3111,20 +3193,20 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
for (Member *m = tstruct->members; m; m = m->next) {
|
||||
if (m->name->len == member->len &&
|
||||
!memcmp(m->name->loc, member->loc, m->name->len)) {
|
||||
return new_num(m->offset, start);
|
||||
return new_ulong(m->offset, start);
|
||||
}
|
||||
}
|
||||
error_tok(member, "no such member");
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_reg_class")) {
|
||||
if (kw == KW___BUILTIN_REG_CLASS) {
|
||||
tok = skip(tok->next, '(');
|
||||
Type *ty = typename(&tok, tok);
|
||||
*rest = skip(tok, ')');
|
||||
if (is_integer(ty) || ty->kind == TY_PTR) return new_num(0, start);
|
||||
if (is_flonum(ty)) return new_num(1, start);
|
||||
return new_num(2, start);
|
||||
if (is_integer(ty) || ty->kind == TY_PTR) return new_int(0, start);
|
||||
if (is_flonum(ty)) return new_int(1, start);
|
||||
return new_int(2, start);
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_compare_and_swap")) {
|
||||
if (kw == KW___BUILTIN_COMPARE_AND_SWAP) {
|
||||
Node *node = new_node(ND_CAS, tok);
|
||||
tok = skip(tok->next, '(');
|
||||
node->cas_addr = assign(&tok, tok);
|
||||
|
@ -3133,18 +3215,20 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
tok = skip(tok, ',');
|
||||
node->cas_new = assign(&tok, tok);
|
||||
*rest = skip(tok, ')');
|
||||
node->ty = node->cas_addr->ty->base;
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_atomic_exchange")) {
|
||||
if (kw == KW___BUILTIN_ATOMIC_EXCHANGE) {
|
||||
Node *node = new_node(ND_EXCH, tok);
|
||||
tok = skip(tok->next, '(');
|
||||
node->lhs = assign(&tok, tok);
|
||||
tok = skip(tok, ',');
|
||||
node->rhs = assign(&tok, tok);
|
||||
node->ty = node->lhs->ty->base;
|
||||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_expect")) { /* do nothing */
|
||||
if (kw == KW___BUILTIN_EXPECT) { /* do nothing */
|
||||
tok = skip(tok->next, '(');
|
||||
Node *node = assign(&tok, tok);
|
||||
tok = skip(tok, ',');
|
||||
|
@ -3152,7 +3236,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_assume_aligned")) { /* do nothing */
|
||||
if (kw == KW___BUILTIN_ASSUME_ALIGNED) { /* do nothing */
|
||||
tok = skip(tok->next, '(');
|
||||
Node *node = assign(&tok, tok);
|
||||
tok = skip(tok, ',');
|
||||
|
@ -3163,16 +3247,16 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_add_overflow")) {
|
||||
if (kw == KW___BUILTIN_ADD_OVERFLOW) {
|
||||
return builtin_overflow(rest, tok, new_add);
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_sub_overflow")) {
|
||||
if (kw == KW___BUILTIN_SUB_OVERFLOW) {
|
||||
return builtin_overflow(rest, tok, new_sub);
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_mul_overflow")) {
|
||||
if (kw == KW___BUILTIN_MUL_OVERFLOW) {
|
||||
return builtin_overflow(rest, tok, new_mul);
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_neg_overflow")) {
|
||||
if (kw == KW___BUILTIN_NEG_OVERFLOW) {
|
||||
Token *start = tok;
|
||||
tok = skip(tok->next, '(');
|
||||
Node *lhs = assign(&tok, tok);
|
||||
|
@ -3189,7 +3273,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
node->ty = copy_type(ty_bool);
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_fpclassify")) {
|
||||
if (kw == KW___BUILTIN_FPCLASSIFY) {
|
||||
Node *node = new_node(ND_FPCLASSIFY, tok);
|
||||
node->fpc = calloc(1, sizeof(FpClassify));
|
||||
node->ty = ty_int;
|
||||
|
@ -3206,7 +3290,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
*rest = skip(tok, ')');
|
||||
return node;
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_popcount")) {
|
||||
if (kw == KW___BUILTIN_POPCOUNT) {
|
||||
Token *t = skip(tok->next, '(');
|
||||
Node *node = assign(&t, t);
|
||||
if (is_const_expr(node)) {
|
||||
|
@ -3214,8 +3298,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_num(__builtin_popcount(eval(node)), t);
|
||||
}
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_popcountl") ||
|
||||
EQUAL(tok, "__builtin_popcountll")) {
|
||||
if (kw == KW___BUILTIN_POPCOUNTL || kw == KW___BUILTIN_POPCOUNTLL) {
|
||||
Token *t = skip(tok->next, '(');
|
||||
Node *node = assign(&t, t);
|
||||
if (is_const_expr(node)) {
|
||||
|
@ -3223,7 +3306,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_num(__builtin_popcountl(eval(node)), t);
|
||||
}
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_ffs")) {
|
||||
if (kw == KW___BUILTIN_FFS) {
|
||||
Token *t = skip(tok->next, '(');
|
||||
Node *node = assign(&t, t);
|
||||
if (is_const_expr(node)) {
|
||||
|
@ -3231,7 +3314,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_num(__builtin_ffs(eval(node)), t);
|
||||
}
|
||||
}
|
||||
if (EQUAL(tok, "__builtin_ffsl") || EQUAL(tok, "__builtin_ffsll")) {
|
||||
if (kw == KW___BUILTIN_FFSL || kw == KW___BUILTIN_FFSLL) {
|
||||
Token *t = skip(tok->next, '(');
|
||||
Node *node = assign(&t, t);
|
||||
if (is_const_expr(node)) {
|
||||
|
@ -3239,16 +3322,13 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_num(__builtin_ffsl(eval(node)), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((EQUAL(tok, "__builtin_strlen") ||
|
||||
(!opt_no_builtin && EQUAL(tok, "strlen"))) &&
|
||||
if ((kw == KW___BUILTIN_STRLEN || (!opt_no_builtin && kw == KW_STRLEN)) &&
|
||||
EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR &&
|
||||
EQUAL(tok->next->next->next, ")")) {
|
||||
*rest = tok->next->next->next->next;
|
||||
return new_num(strlen(tok->next->next->str), tok);
|
||||
}
|
||||
if ((EQUAL(tok, "__builtin_strpbrk") ||
|
||||
(!opt_no_builtin && EQUAL(tok, "strpbrk")))) {
|
||||
if ((kw == KW___BUILTIN_STRPBRK || (!opt_no_builtin && kw == KW_STRPBRK))) {
|
||||
if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR &&
|
||||
EQUAL(tok->next->next->next, ",") &&
|
||||
tok->next->next->next->next->kind == TK_STR &&
|
||||
|
@ -3264,8 +3344,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((EQUAL(tok, "__builtin_strstr") ||
|
||||
(!opt_no_builtin && EQUAL(tok, "strstr")))) {
|
||||
if (kw == KW___BUILTIN_STRSTR || (!opt_no_builtin && kw == KW_STRSTR)) {
|
||||
if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR &&
|
||||
EQUAL(tok->next->next->next, ",") &&
|
||||
tok->next->next->next->next->kind == TK_STR &&
|
||||
|
@ -3281,8 +3360,7 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((EQUAL(tok, "__builtin_strchr") ||
|
||||
(!opt_no_builtin && EQUAL(tok, "strchr")))) {
|
||||
if (kw == KW___BUILTIN_STRCHR || (!opt_no_builtin && kw == KW_STRCHR)) {
|
||||
if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR &&
|
||||
EQUAL(tok->next->next->next, ",") &&
|
||||
tok->next->next->next->next->kind == TK_NUM &&
|
||||
|
@ -3298,10 +3376,18 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tok->kind == TK_IDENT) {
|
||||
// Variable or enum constant
|
||||
VarScope *sc = find_var(tok);
|
||||
*rest = tok->next;
|
||||
#ifdef IMPLICIT_FUNCTIONS
|
||||
if (!sc && EQUAL(tok->next, "(")) {
|
||||
Type *ty = func_type(ty_long);
|
||||
ty->is_variadic = true;
|
||||
return new_var_node(new_gvar(strndup(tok->loc, tok->len), ty), tok);
|
||||
}
|
||||
#endif
|
||||
// For "static inline" function
|
||||
if (sc && sc->var && sc->var->is_function) {
|
||||
if (current_fn) {
|
||||
|
@ -3606,11 +3692,11 @@ void declare_builtin_functions(void) {
|
|||
declare0("trap", ty_int);
|
||||
declare0("unreachable", ty_int);
|
||||
declare1("ctz", ty_int, ty_int);
|
||||
declare1("ctzl", ty_long, ty_long);
|
||||
declare1("ctzll", ty_long, ty_long);
|
||||
declare1("ctzl", ty_int, ty_long);
|
||||
declare1("ctzll", ty_int, ty_long);
|
||||
declare1("clz", ty_int, ty_int);
|
||||
declare1("clzl", ty_long, ty_long);
|
||||
declare1("clzll", ty_long, ty_long);
|
||||
declare1("clzl", ty_int, ty_long);
|
||||
declare1("clzll", ty_int, ty_long);
|
||||
declare1("ffs", ty_int, ty_int);
|
||||
declare1("ffsl", ty_int, ty_long);
|
||||
declare1("ffsll", ty_int, ty_long);
|
||||
|
|
136
third_party/chibicc/preprocess.c
vendored
136
third_party/chibicc/preprocess.c
vendored
|
@ -22,7 +22,11 @@
|
|||
// standard's wording:
|
||||
// https://github.com/rui314/chibicc/wiki/cpp.algo.pdf
|
||||
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/mem/arena.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
#include "third_party/chibicc/kw.h"
|
||||
|
||||
typedef struct CondIncl CondIncl;
|
||||
typedef struct Hideset Hideset;
|
||||
|
@ -65,8 +69,8 @@ static int include_next_idx;
|
|||
static Token *preprocess2(Token *);
|
||||
static Macro *find_macro(Token *);
|
||||
|
||||
static bool is_hash(Token *tok) {
|
||||
return tok->at_bol && EQUAL(tok, "#");
|
||||
static inline bool is_hash(Token *tok) {
|
||||
return tok->at_bol && tok->len == 1 && tok->loc[0] == '#';
|
||||
}
|
||||
|
||||
// Some preprocessor directives such as #include allow extraneous
|
||||
|
@ -151,13 +155,17 @@ static Token *append(Token *tok1, Token *tok2) {
|
|||
}
|
||||
|
||||
static Token *skip_cond_incl2(Token *tok) {
|
||||
unsigned char kw;
|
||||
while (tok->kind != TK_EOF) {
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
|
||||
EQUAL(tok->next, "ifndef"))) {
|
||||
if (is_hash(tok) && (kw = GetKw(tok->next->loc, tok->next->len))) {
|
||||
if (kw == KW_IF || kw == KW_IFDEF || kw == KW_IFNDEF) {
|
||||
tok = skip_cond_incl2(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
if (is_hash(tok) && EQUAL(tok->next, "endif")) return tok->next->next;
|
||||
if (kw == KW_ENDIF) {
|
||||
return tok->next->next;
|
||||
}
|
||||
}
|
||||
tok = tok->next;
|
||||
}
|
||||
return tok;
|
||||
|
@ -166,15 +174,17 @@ static Token *skip_cond_incl2(Token *tok) {
|
|||
// Skip until next `#else`, `#elif` or `#endif`.
|
||||
// Nested `#if` and `#endif` are skipped.
|
||||
static Token *skip_cond_incl(Token *tok) {
|
||||
unsigned char kw;
|
||||
while (tok->kind != TK_EOF) {
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
|
||||
EQUAL(tok->next, "ifndef"))) {
|
||||
if (is_hash(tok) && (kw = GetKw(tok->next->loc, tok->next->len))) {
|
||||
if (kw == KW_IF || kw == KW_IFDEF || kw == KW_IFNDEF) {
|
||||
tok = skip_cond_incl2(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "elif") || EQUAL(tok->next, "else") ||
|
||||
EQUAL(tok->next, "endif")))
|
||||
if (kw == KW_ELIF || kw == KW_ELSE || kw == KW_ENDIF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tok = tok->next;
|
||||
}
|
||||
return tok;
|
||||
|
@ -210,14 +220,20 @@ static Token *new_str_token(char *str, Token *tmpl) {
|
|||
static Token *copy_line(Token **rest, Token *tok) {
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
for (; !tok->at_bol; tok = tok->next) cur = cur->next = copy_token(tok);
|
||||
for (; !tok->at_bol; tok = tok->next) {
|
||||
cur = cur->next = copy_token(tok);
|
||||
}
|
||||
cur->next = new_eof(tok);
|
||||
*rest = tok;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
static Token *new_num_token(int val, Token *tmpl) {
|
||||
char *buf = xasprintf("%d\n", val);
|
||||
char *p, *buf;
|
||||
p = buf = malloc(13);
|
||||
p = FormatInt32(p, val);
|
||||
p[0] = '\n';
|
||||
p[1] = 0;
|
||||
return tokenize(new_file(tmpl->file->name, tmpl->file->file_no, buf));
|
||||
}
|
||||
|
||||
|
@ -248,6 +264,7 @@ static Token *read_const_expr(Token **rest, Token *tok) {
|
|||
|
||||
// Read and evaluate a constant expression.
|
||||
static long eval_const_expr(Token **rest, Token *tok) {
|
||||
__arena_push();
|
||||
Token *start = tok;
|
||||
Token *expr = read_const_expr(rest, tok->next);
|
||||
expr = preprocess2(expr);
|
||||
|
@ -268,6 +285,7 @@ static long eval_const_expr(Token **rest, Token *tok) {
|
|||
Token *rest2;
|
||||
long val = const_expr(&rest2, expr);
|
||||
if (rest2->kind != TK_EOF) error_tok(rest2, "extra token");
|
||||
__arena_pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -327,7 +345,7 @@ static Macro *read_macro_definition(Token **rest, Token *tok) {
|
|||
if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier");
|
||||
name = strndup(tok->loc, tok->len);
|
||||
tok = tok->next;
|
||||
if (!tok->has_space && EQUAL(tok, "(")) {
|
||||
if (!tok->has_space && tok->len == 1 && tok->loc[0] == '(') {
|
||||
// Function-like macro
|
||||
char *va_args_name = NULL;
|
||||
MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
|
||||
|
@ -346,13 +364,18 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
|
|||
Token *cur = &head;
|
||||
int level = 0;
|
||||
for (;;) {
|
||||
if (level == 0 && EQUAL(tok, ")")) break;
|
||||
if (level == 0 && !read_rest && EQUAL(tok, ",")) break;
|
||||
if (level == 0 && tok->len == 1 && tok->loc[0] == ')') {
|
||||
break;
|
||||
}
|
||||
if (level == 0 && !read_rest && tok->len == 1 && tok->loc[0] == ',') {
|
||||
break;
|
||||
}
|
||||
if (tok->kind == TK_EOF) error_tok(tok, "premature end of input");
|
||||
if (EQUAL(tok, "("))
|
||||
if (tok->len == 1 && tok->loc[0] == '(') {
|
||||
level++;
|
||||
else if (EQUAL(tok, ")"))
|
||||
} else if (tok->len == 1 && tok->loc[0] == ')') {
|
||||
level--;
|
||||
}
|
||||
cur = cur->next = copy_token(tok);
|
||||
tok = tok->next;
|
||||
}
|
||||
|
@ -377,7 +400,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params,
|
|||
}
|
||||
if (va_args_name) {
|
||||
MacroArg *arg;
|
||||
if (EQUAL(tok, ")")) {
|
||||
if (tok->len == 1 && tok->loc[0] == ')') {
|
||||
arg = calloc(1, sizeof(MacroArg));
|
||||
arg->tok = new_eof(tok);
|
||||
} else {
|
||||
|
@ -461,10 +484,11 @@ static Token *subst(Token *tok, MacroArg *args) {
|
|||
Token *cur = &head;
|
||||
while (tok->kind != TK_EOF) {
|
||||
// "#" followed by a parameter is replaced with stringized actuals.
|
||||
if (EQUAL(tok, "#")) {
|
||||
if (tok->len == 1 && tok->loc[0] == '#') {
|
||||
MacroArg *arg = find_arg(args, tok->next);
|
||||
if (!arg)
|
||||
if (!arg) {
|
||||
error_tok(tok->next, "'#' is not followed by a macro parameter");
|
||||
}
|
||||
cur = cur->next = stringize(tok, arg->tok);
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
|
@ -472,7 +496,9 @@ static Token *subst(Token *tok, MacroArg *args) {
|
|||
// [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded
|
||||
// to the empty token list. Otherwise, its expaned to `,` and
|
||||
// __VA_ARGS__.
|
||||
if (EQUAL(tok, ",") && EQUAL(tok->next, "##")) {
|
||||
if (tok->len == 1 && tok->loc[0] == ',' &&
|
||||
(tok->next->len == 2 &&
|
||||
(tok->next->loc[0] == '#' && tok->next->loc[1] == '#'))) {
|
||||
MacroArg *arg = find_arg(args, tok->next->next);
|
||||
if (arg && arg->is_va_args) {
|
||||
if (arg->tok->kind == TK_EOF) {
|
||||
|
@ -484,7 +510,7 @@ static Token *subst(Token *tok, MacroArg *args) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (EQUAL(tok, "##")) {
|
||||
if (tok->len == 2 && tok->loc[0] == '#' && tok->loc[1] == '#') {
|
||||
if (cur == &head)
|
||||
error_tok(tok, "'##' cannot appear at start of macro expansion");
|
||||
if (tok->next->kind == TK_EOF)
|
||||
|
@ -504,7 +530,8 @@ static Token *subst(Token *tok, MacroArg *args) {
|
|||
continue;
|
||||
}
|
||||
MacroArg *arg = find_arg(args, tok);
|
||||
if (arg && EQUAL(tok->next, "##")) {
|
||||
if (arg && (tok->next->len == 2 &&
|
||||
(tok->next->loc[0] == '#' && tok->next->loc[1] == '#'))) {
|
||||
Token *rhs = tok->next->next;
|
||||
if (arg->tok->kind == TK_EOF) {
|
||||
MacroArg *arg2 = find_arg(args, rhs);
|
||||
|
@ -577,7 +604,7 @@ static bool expand_macro(Token **rest, Token *tok) {
|
|||
}
|
||||
// If a funclike macro token is not followed by an argument list,
|
||||
// treat it as a normal identifier.
|
||||
if (!EQUAL(tok->next, "(")) return false;
|
||||
if (!(tok->next->len == 1 && tok->next->loc[0] == '(')) return false;
|
||||
// Function-like macro application
|
||||
Token *macro_token = tok;
|
||||
MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name);
|
||||
|
@ -709,6 +736,7 @@ static Token *include_file(Token *tok, char *path, Token *filename_tok) {
|
|||
|
||||
// Read #line arguments
|
||||
static void read_line_marker(Token **rest, Token *tok) {
|
||||
// TODO: This is broken if file is different? See gperf codegen.
|
||||
Token *start = tok;
|
||||
tok = preprocess(copy_line(rest, tok));
|
||||
if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)
|
||||
|
@ -723,6 +751,7 @@ static void read_line_marker(Token **rest, Token *tok) {
|
|||
// Visit all tokens in `tok` while evaluating preprocessing
|
||||
// macros and directives.
|
||||
static Token *preprocess2(Token *tok) {
|
||||
unsigned char kw;
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
while (tok->kind != TK_EOF) {
|
||||
|
@ -744,13 +773,17 @@ static Token *preprocess2(Token *tok) {
|
|||
}
|
||||
Token *start = tok;
|
||||
tok = tok->next;
|
||||
if (EQUAL(tok, "include")) {
|
||||
if ((kw = GetKw(tok->loc, tok->len))) {
|
||||
if (kw == KW_INCLUDE) {
|
||||
bool is_dquote;
|
||||
char *filename = read_include_filename(&tok, tok->next, &is_dquote);
|
||||
if (filename[0] != '/' && is_dquote) {
|
||||
char *path =
|
||||
xasprintf("%s/%s", dirname(strdup(start->file->name)), filename);
|
||||
if (fileexists(path)) {
|
||||
char *tmp = strdup(start->file->name);
|
||||
char *path = xasprintf("%s/%s", dirname(tmp), filename);
|
||||
free(tmp);
|
||||
bool exists = fileexists(path);
|
||||
free(path);
|
||||
if (exists) {
|
||||
tok = include_file(tok, path, start->next->next);
|
||||
continue;
|
||||
}
|
||||
|
@ -759,18 +792,18 @@ static Token *preprocess2(Token *tok) {
|
|||
tok = include_file(tok, path ? path : filename, start->next->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "include_next")) {
|
||||
if (kw == KW_INCLUDE_NEXT) {
|
||||
bool ignore;
|
||||
char *filename = read_include_filename(&tok, tok->next, &ignore);
|
||||
char *path = search_include_next(filename);
|
||||
tok = include_file(tok, path ? path : filename, start->next->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "define")) {
|
||||
if (kw == KW_DEFINE) {
|
||||
read_macro_definition(&tok, tok->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "undef")) {
|
||||
if (kw == KW_UNDEF) {
|
||||
tok = tok->next;
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "macro name must be an identifier");
|
||||
|
@ -778,27 +811,27 @@ static Token *preprocess2(Token *tok) {
|
|||
tok = skip_line(tok->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "if")) {
|
||||
if (kw == KW_IF) {
|
||||
long val = eval_const_expr(&tok, tok);
|
||||
push_cond_incl(start, val);
|
||||
if (!val) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "ifdef")) {
|
||||
if (kw == KW_IFDEF) {
|
||||
bool defined = find_macro(tok->next);
|
||||
push_cond_incl(tok, defined);
|
||||
tok = skip_line(tok->next->next);
|
||||
if (!defined) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "ifndef")) {
|
||||
if (kw == KW_IFNDEF) {
|
||||
bool defined = find_macro(tok->next);
|
||||
push_cond_incl(tok, !defined);
|
||||
tok = skip_line(tok->next->next);
|
||||
if (defined) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "elif")) {
|
||||
if (kw == KW_ELIF) {
|
||||
if (!cond_incl || cond_incl->ctx == IN_ELSE)
|
||||
error_tok(start, "stray #elif");
|
||||
cond_incl->ctx = IN_ELIF;
|
||||
|
@ -808,7 +841,7 @@ static Token *preprocess2(Token *tok) {
|
|||
tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "else")) {
|
||||
if (kw == KW_ELSE) {
|
||||
if (!cond_incl || cond_incl->ctx == IN_ELSE)
|
||||
error_tok(start, "stray #else");
|
||||
cond_incl->ctx = IN_ELSE;
|
||||
|
@ -816,32 +849,35 @@ static Token *preprocess2(Token *tok) {
|
|||
if (cond_incl->included) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "endif")) {
|
||||
if (kw == KW_ENDIF) {
|
||||
if (!cond_incl) error_tok(start, "stray #endif");
|
||||
cond_incl = cond_incl->next;
|
||||
tok = skip_line(tok->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "line")) {
|
||||
if (kw == KW_LINE) {
|
||||
read_line_marker(&tok, tok->next);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (tok->kind == TK_PP_NUM) {
|
||||
read_line_marker(&tok, tok);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "pragma") && EQUAL(tok->next, "once")) {
|
||||
if (kw == KW_PRAGMA && EQUAL(tok->next, "once")) {
|
||||
hashmap_put(&pragma_once, tok->file->name, (void *)1);
|
||||
tok = skip_line(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "pragma")) {
|
||||
if (kw == KW_PRAGMA) {
|
||||
do {
|
||||
tok = tok->next;
|
||||
} while (!tok->at_bol);
|
||||
continue;
|
||||
}
|
||||
if (EQUAL(tok, "error")) error_tok(tok, "error");
|
||||
if (kw == KW_ERROR) {
|
||||
error_tok(tok, "error");
|
||||
}
|
||||
// `#`-only line is legal. It's called a null directive.
|
||||
if (tok->at_bol) continue;
|
||||
error_tok(tok, "invalid preprocessor directive");
|
||||
|
@ -901,11 +937,7 @@ static Token *base_file_macro(Token *tmpl) {
|
|||
|
||||
// __DATE__ is expanded to the current date, e.g. "May 17 2020".
|
||||
static char *format_date(struct tm *tm) {
|
||||
_Alignas(char) static char mon[][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
};
|
||||
return xasprintf("\"%s %2d %d\"", mon[tm->tm_mon], tm->tm_mday,
|
||||
return xasprintf("\"%s %2d %d\"", kMonthNameShort[tm->tm_mon], tm->tm_mday,
|
||||
tm->tm_year + 1900);
|
||||
}
|
||||
|
||||
|
@ -914,6 +946,15 @@ static char *format_time(struct tm *tm) {
|
|||
return xasprintf("\"%02d:%02d:%02d\"", tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
|
||||
void init_macros_conditional(void) {
|
||||
if (opt_pg) define_macro("__PG__", "1");
|
||||
if (opt_pic) define_macro("__PIC__", "1");
|
||||
if (opt_sse3) define_macro("__SSE3__", "1");
|
||||
if (opt_sse4) define_macro("__SSE4__", "1");
|
||||
if (opt_popcnt) define_macro("__POPCNT__", "1");
|
||||
if (opt_fentry) define_macro("__MFENTRY__", "1");
|
||||
}
|
||||
|
||||
void init_macros(void) {
|
||||
char *val, *name = "\
|
||||
__chibicc__\000\
|
||||
|
@ -1232,9 +1273,6 @@ __SSE2_MATH__\000\
|
|||
define_macro(name, val);
|
||||
name = val + strlen(val) + 1;
|
||||
} while (*name);
|
||||
#ifdef __SSE3__
|
||||
define_macro("__SSE3__", "1");
|
||||
#endif
|
||||
add_builtin("__FILE__", file_macro);
|
||||
add_builtin("__LINE__", line_macro);
|
||||
add_builtin("__COUNTER__", counter_macro);
|
||||
|
@ -1306,8 +1344,10 @@ static void join_adjacent_string_literals(Token *tok) {
|
|||
len = len + t->ty->array_len - 1;
|
||||
}
|
||||
char *buf = calloc(tok1->ty->base->size, len);
|
||||
int j = 0;
|
||||
int i = 0;
|
||||
for (Token *t = tok1; t != tok2; t = t->next) {
|
||||
++j;
|
||||
memcpy(buf + i, t->str, t->ty->size);
|
||||
i = i + t->ty->size - t->ty->base->size;
|
||||
}
|
||||
|
|
2
third_party/chibicc/printast.c
vendored
2
third_party/chibicc/printast.c
vendored
|
@ -130,6 +130,8 @@ static void PrintType(FILE *f, int l, const char *s, Type *t) {
|
|||
PrintBool(f, l + 2, "is_flexible: ", t->is_flexible);
|
||||
PrintBool(f, l + 2, "is_packed: ", t->is_packed);
|
||||
PrintBool(f, l + 2, "is_aligned: ", t->is_aligned);
|
||||
PrintBool(f, l + 2, "is_const: ", t->is_const);
|
||||
PrintBool(f, l + 2, "is_static: ", t->is_static);
|
||||
PrintType(f, l + 2, "return_ty: ", t->return_ty);
|
||||
PrintType(f, l + 2, "params: ", t->params);
|
||||
PrintBool(f, l + 2, "is_variadic: ", t->is_variadic);
|
||||
|
|
547
third_party/chibicc/pybind.c
vendored
Normal file
547
third_party/chibicc/pybind.c
vendored
Normal file
|
@ -0,0 +1,547 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
static void AppendStringLiteral(char **b, const char *s, const char *indent) {
|
||||
int c, w, l, o;
|
||||
for (o = l = 0;; l = c) {
|
||||
switch ((c = *s++ & 255)) {
|
||||
case 0:
|
||||
return;
|
||||
case '\r':
|
||||
continue;
|
||||
case '\t':
|
||||
w = READ16LE("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
w = READ32LE("\\n\\\n");
|
||||
break;
|
||||
case '"':
|
||||
w = READ16LE("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
w = READ16LE("\\\\");
|
||||
break;
|
||||
case '`':
|
||||
/* convert markdown <code> to restructured text */
|
||||
if (o) {
|
||||
o = 0;
|
||||
w = READ16LE("''");
|
||||
} else if (*s == '`') {
|
||||
w = '`';
|
||||
++s;
|
||||
} else {
|
||||
o = 1;
|
||||
w = READ16LE("``");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((0x00 <= c && c <= 0x1F) || c == 0x7F || (c == '?' && l == '?')) {
|
||||
w = '\\';
|
||||
w |= ('0' + ((c & 0300) >> 6)) << 010;
|
||||
w |= ('0' + ((c & 0070) >> 3)) << 020;
|
||||
w |= ('0' + ((c & 0007) >> 0)) << 030;
|
||||
} else {
|
||||
w = c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
appendw(b, w);
|
||||
if (c == '\n' && indent) {
|
||||
appends(b, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendJavadown(char **b, const struct Javadown *j) {
|
||||
size_t i;
|
||||
const char *s, *s2;
|
||||
if (j->title && *j->title) {
|
||||
AppendStringLiteral(b, j->title, 0);
|
||||
if (j->text && *j->text) {
|
||||
appendw(b, READ32LE("\\n\\\n"));
|
||||
appendw(b, READ32LE("\\n\\\n"));
|
||||
}
|
||||
}
|
||||
if (j->text && *j->text) {
|
||||
AppendStringLiteral(b, j->text, 0);
|
||||
}
|
||||
if (j->tags.n) {
|
||||
appendw(b, READ32LE("\\n\\\n"));
|
||||
for (i = 0; i < j->tags.n; ++i) {
|
||||
appendw(b, READ64LE("\\n\\\n:\0\0"));
|
||||
AppendStringLiteral(b, j->tags.p[i].tag, 0);
|
||||
s = j->tags.p[i].text;
|
||||
if (!strcmp(j->tags.p[i].tag, "param") && s && (s2 = strchr(s, ' '))) {
|
||||
appendw(b, ' ');
|
||||
appendd(b, s, s2 - s);
|
||||
s = s2 + 1;
|
||||
}
|
||||
appendw(b, ':');
|
||||
if (s && *s) {
|
||||
appendw(b, ' ');
|
||||
AppendStringLiteral(b, s, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendScalar(char **b, struct Type *ty, char *name, int i) {
|
||||
if (ty->is_atomic) appendw(b, READ64LE("_Atomic "));
|
||||
if (i && ty->is_const) appendw(b, READ64LE("const \0"));
|
||||
if (ty->is_unsigned) appends(b, "unsigned ");
|
||||
appends(b, name);
|
||||
}
|
||||
|
||||
static void AppendType(char **b, struct Type *ty, int i) {
|
||||
switch (ty->kind) {
|
||||
case TY_VOID:
|
||||
appends(b, "void");
|
||||
break;
|
||||
case TY_BOOL:
|
||||
appends(b, "_Bool");
|
||||
break;
|
||||
case TY_CHAR:
|
||||
AppendScalar(b, ty, "char", i);
|
||||
break;
|
||||
case TY_SHORT:
|
||||
AppendScalar(b, ty, "short", i);
|
||||
break;
|
||||
case TY_INT:
|
||||
case TY_ENUM:
|
||||
AppendScalar(b, ty, "int", i);
|
||||
break;
|
||||
case TY_LONG:
|
||||
AppendScalar(b, ty, "long", i);
|
||||
break;
|
||||
case TY_INT128:
|
||||
AppendScalar(b, ty, "__int128", i);
|
||||
break;
|
||||
case TY_FLOAT:
|
||||
AppendScalar(b, ty, "float", i);
|
||||
break;
|
||||
case TY_DOUBLE:
|
||||
AppendScalar(b, ty, "double", i);
|
||||
break;
|
||||
case TY_LDOUBLE:
|
||||
AppendScalar(b, ty, "long double", i);
|
||||
break;
|
||||
case TY_FUNC:
|
||||
AppendType(b, ty->return_ty, i);
|
||||
appends(b, " (*)()");
|
||||
break;
|
||||
case TY_PTR:
|
||||
if (!ty->array_len) {
|
||||
AppendType(b, ty->base, i + 1);
|
||||
if (ty->base->kind != TY_FUNC) {
|
||||
appendw(b, '*');
|
||||
if (i && ty->is_const) appendw(b, READ64LE(" const\0"));
|
||||
if (ty->is_restrict) appends(b, " restrict");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* undecay */
|
||||
case TY_ARRAY:
|
||||
AppendType(b, ty->base, i + 1);
|
||||
appendw(b, '[');
|
||||
if (!i && ty->is_static) appendw(b, READ64LE("static "));
|
||||
if (!i && ty->is_restrict) appends(b, "restrict ");
|
||||
appendf(b, "%lu", ty->array_len);
|
||||
appendw(b, ']');
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSupportedReturnType(struct Type *ty) {
|
||||
switch (ty->kind) {
|
||||
case TY_VOID:
|
||||
case TY_BOOL:
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
case TY_INT:
|
||||
case TY_LONG:
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
return true;
|
||||
case TY_PTR:
|
||||
if (ty->base->kind == TY_CHAR) {
|
||||
return !ty->base->is_unsigned;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSupportedParameterType(struct Type *ty) {
|
||||
switch (ty->kind) {
|
||||
case TY_BOOL:
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
case TY_INT:
|
||||
case TY_LONG:
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
return true;
|
||||
case TY_PTR:
|
||||
if (ty->base->kind == TY_CHAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool Reject(char **b, struct Obj *obj, struct Type *ty,
|
||||
const char *reason) {
|
||||
appendf(b, "\n/* %s: %s: ", obj->name, reason);
|
||||
AppendType(b, ty, 0);
|
||||
appendw(b, READ32LE(" */\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsFunctionSupported(char **b, struct Obj *func) {
|
||||
Obj *param;
|
||||
if (!IsSupportedReturnType(func->ty->return_ty)) {
|
||||
return Reject(b, func, func->ty->return_ty, "unsupported return type");
|
||||
}
|
||||
for (param = func->params; param; param = param->next) {
|
||||
if (!IsSupportedParameterType(param->ty)) {
|
||||
return Reject(b, func, param->ty, "unsupported parameter type");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int GetParamDirective(struct Obj **param) {
|
||||
bool is_unsigned;
|
||||
is_unsigned = (*param)->ty->is_unsigned;
|
||||
switch ((*param)->ty->kind) {
|
||||
case TY_BOOL:
|
||||
return 'p';
|
||||
case TY_CHAR:
|
||||
return is_unsigned ? 'B' : 'b';
|
||||
case TY_SHORT:
|
||||
return is_unsigned ? 'H' : 'h';
|
||||
case TY_INT:
|
||||
return is_unsigned ? 'I' : 'i';
|
||||
case TY_LONG:
|
||||
return is_unsigned ? 'L' : 'l';
|
||||
case TY_FLOAT:
|
||||
return 'f';
|
||||
case TY_DOUBLE:
|
||||
return 'd';
|
||||
case TY_PTR:
|
||||
if ((*param)->ty->base->kind == TY_CHAR) {
|
||||
if ((*param)->ty->base->is_unsigned &&
|
||||
((*param)->next && ((*param)->next->ty->kind == TY_LONG &&
|
||||
(*param)->next->ty->is_unsigned))) {
|
||||
*param = (*param)->next;
|
||||
return READ16LE("y*");
|
||||
} else {
|
||||
return READ16LE("s*");
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static char *GetParamIntermediate(struct Obj **param) {
|
||||
bool is_unsigned;
|
||||
is_unsigned = (*param)->ty->is_unsigned;
|
||||
switch ((*param)->ty->kind) {
|
||||
case TY_BOOL:
|
||||
return "int";
|
||||
case TY_CHAR:
|
||||
return is_unsigned ? "unsigned char" : "signed char";
|
||||
case TY_SHORT:
|
||||
return is_unsigned ? "unsigned short" : "short";
|
||||
case TY_INT:
|
||||
return is_unsigned ? "unsigned" : "int";
|
||||
case TY_LONG:
|
||||
return is_unsigned ? "unsigned long" : "long";
|
||||
case TY_FLOAT:
|
||||
return "float";
|
||||
case TY_DOUBLE:
|
||||
return "float";
|
||||
case TY_PTR:
|
||||
if ((*param)->ty->base->kind == TY_CHAR) {
|
||||
*param = (*param)->next;
|
||||
return "Py_buffer";
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static const char *GetReturnIntermediate(struct Type *ty) {
|
||||
bool is_unsigned;
|
||||
is_unsigned = ty->is_unsigned;
|
||||
switch (ty->kind) {
|
||||
case TY_BOOL:
|
||||
return "int";
|
||||
case TY_CHAR:
|
||||
return is_unsigned ? "unsigned char" : "signed char";
|
||||
case TY_SHORT:
|
||||
return is_unsigned ? "unsigned short" : "short";
|
||||
case TY_INT:
|
||||
return is_unsigned ? "unsigned" : "int";
|
||||
case TY_LONG:
|
||||
return is_unsigned ? "unsigned long" : "long";
|
||||
case TY_FLOAT:
|
||||
return "float";
|
||||
case TY_DOUBLE:
|
||||
return "float";
|
||||
case TY_PTR:
|
||||
if (ty->base->kind == TY_CHAR) {
|
||||
if (ty->base->is_const) {
|
||||
return "const char*";
|
||||
} else {
|
||||
return "char*";
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendFunction(char **b, Obj *func, const char *module) {
|
||||
Obj *param;
|
||||
const char *name;
|
||||
appendf(b, "\nPyDoc_STRVAR(pb_%s_%s_doc,\n\"%s($module", module, func->name,
|
||||
func->name);
|
||||
for (param = func->params; param; param = param->next) {
|
||||
appendw(b, READ16LE(", "));
|
||||
appends(b, param->name);
|
||||
}
|
||||
appends(b, ")");
|
||||
if (func->javadown) {
|
||||
appends(b, "\\n\\\n--\\n\\n\\\n");
|
||||
AppendJavadown(b, func->javadown->javadown);
|
||||
}
|
||||
appendw(b, READ32LE("\");\n\n"));
|
||||
AppendType(b, func->ty->return_ty, 0);
|
||||
appendw(b, ' ');
|
||||
appends(b, func->name);
|
||||
appendw(b, '(');
|
||||
if (func->params) {
|
||||
AppendType(b, func->params->ty, 0);
|
||||
for (param = func->params->next; param; param = param->next) {
|
||||
appendw(b, READ16LE(", "));
|
||||
AppendType(b, param->ty, 0);
|
||||
}
|
||||
} else {
|
||||
appendw(b, READ32LE("void"));
|
||||
}
|
||||
appendw(b, READ32LE(");\n\n"));
|
||||
appends(b, "static PyObject*\n");
|
||||
appendf(b, "pb_%s_%s(PyObject* self_, PyObject* args_)\n", module,
|
||||
func->name);
|
||||
appendw(b, READ16LE("{\n"));
|
||||
appendw(b, READ32LE(" "));
|
||||
appends(b, "PyObject* res_;\n");
|
||||
if (func->ty->return_ty->kind != TY_VOID) {
|
||||
appendw(b, READ32LE(" "));
|
||||
appends(b, GetReturnIntermediate(func->ty->return_ty));
|
||||
appendw(b, READ64LE(" ret_;\n"));
|
||||
}
|
||||
if (func->params) {
|
||||
for (param = func->params; param; param = param->next) {
|
||||
name = param->name;
|
||||
appendw(b, READ32LE(" "));
|
||||
appends(b, GetParamIntermediate(¶m));
|
||||
appendw(b, ' ');
|
||||
appends(b, name);
|
||||
appendw(b, READ16LE(";\n"));
|
||||
if (!param) break;
|
||||
}
|
||||
appends(b, " if (!PyArg_ParseTuple(args_, \"");
|
||||
for (param = func->params; param; param = param->next) {
|
||||
appendw(b, GetParamDirective(¶m));
|
||||
if (!param) break;
|
||||
}
|
||||
appendf(b, ":%s\"", func->name);
|
||||
for (param = func->params; param; param = param->next) {
|
||||
appendf(b, ", &%s", param->name);
|
||||
}
|
||||
appends(b, ")) return 0;\n");
|
||||
}
|
||||
appendw(b, READ32LE(" "));
|
||||
if (func->ty->return_ty->kind != TY_VOID) {
|
||||
appendw(b, READ64LE("ret_ = "));
|
||||
}
|
||||
appends(b, func->name);
|
||||
appendw(b, '(');
|
||||
for (param = func->params; param; param = param->next) {
|
||||
if (param != func->params) {
|
||||
appendw(b, READ16LE(", "));
|
||||
}
|
||||
appends(b, param->name);
|
||||
if (param->ty->kind == TY_PTR && param->ty->base->kind == TY_CHAR) {
|
||||
appendw(b, READ32LE(".buf"));
|
||||
if (param->ty->base->is_unsigned &&
|
||||
(param->next && (param->next->ty->kind == TY_LONG &&
|
||||
param->next->ty->is_unsigned))) {
|
||||
appendf(b, ", %s.len", param->name);
|
||||
param = param->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
appends(b, ");\n");
|
||||
switch (func->ty->return_ty->kind) {
|
||||
case TY_VOID:
|
||||
appends(b, " res_ = Py_None;\n");
|
||||
appends(b, " Py_INCREF(res_);\n");
|
||||
break;
|
||||
case TY_BOOL:
|
||||
appends(b, " res_ = ret_ ? Py_True : Py_False;\n");
|
||||
appends(b, " Py_INCREF(res_);\n");
|
||||
break;
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
case TY_INT:
|
||||
appends(b, " res_ = PyLong_FromLong(ret_);\n");
|
||||
break;
|
||||
case TY_LONG:
|
||||
if (func->ty->return_ty->is_unsigned) {
|
||||
appends(b, " res_ = PyLong_FromUnsignedLong(ret_);\n");
|
||||
} else {
|
||||
appends(b, " res_ = PyLong_FromLong(ret_);\n");
|
||||
}
|
||||
break;
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
appends(b, " res_ = PyFloat_FromDouble(ret_);\n");
|
||||
break;
|
||||
case TY_PTR:
|
||||
appends(b, "\
|
||||
if (ret_) {\n\
|
||||
res_ = PyUnicode_DecodeUTF8(ret_, strlen(ret_), 0);\n\
|
||||
} else {\n\
|
||||
res_ = Py_None;\n\
|
||||
Py_INCREF(res_);\n\
|
||||
}\n");
|
||||
if (!func->ty->return_ty->base->is_const) {
|
||||
appends(b, " free(res_);\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
for (param = func->params; param; param = param->next) {
|
||||
if (param->ty->kind == TY_PTR && param->ty->base->kind == TY_CHAR) {
|
||||
appendf(b, " PyBuffer_Release(&%s);\n", param->name);
|
||||
}
|
||||
}
|
||||
appends(b, " return res_;\n");
|
||||
appendw(b, READ16LE("}\n"));
|
||||
}
|
||||
|
||||
void output_bindings_python(const char *path, Obj *prog, Token *tok) {
|
||||
int fd;
|
||||
Obj *obj;
|
||||
char *b = 0;
|
||||
char *bm = 0;
|
||||
const char *module;
|
||||
module = basename(stripexts(strdup(tok->file->name)));
|
||||
appends(&b, "\
|
||||
#define PY_SSIZE_T_CLEAN\n\
|
||||
#include \"third_party/python/Include/abstract.h\"\n\
|
||||
#include \"third_party/python/Include/boolobject.h\"\n\
|
||||
#include \"third_party/python/Include/floatobject.h\"\n\
|
||||
#include \"third_party/python/Include/import.h\"\n\
|
||||
#include \"third_party/python/Include/longobject.h\"\n\
|
||||
#include \"third_party/python/Include/methodobject.h\"\n\
|
||||
#include \"third_party/python/Include/modsupport.h\"\n\
|
||||
#include \"third_party/python/Include/moduleobject.h\"\n\
|
||||
#include \"third_party/python/Include/pymacro.h\"\n\
|
||||
#include \"third_party/python/Include/pyport.h\"\n\
|
||||
");
|
||||
if (tok->file->javadown) {
|
||||
appendf(&b, "\nPyDoc_STRVAR(pb_%s_doc,\n\"", module);
|
||||
AppendJavadown(&b, tok->file->javadown);
|
||||
appendw(&b, READ32LE("\");\n"));
|
||||
}
|
||||
for (obj = prog; obj; obj = obj->next) {
|
||||
if (obj->is_function) {
|
||||
if (obj->is_static) continue;
|
||||
if (!obj->is_definition) continue;
|
||||
if (*obj->name == '_') continue;
|
||||
if (strchr(obj->name, '$')) continue;
|
||||
if (!IsFunctionSupported(&b, obj)) continue;
|
||||
AppendFunction(&b, obj, module);
|
||||
appendf(&bm, " {\"%s\", pb_%s_%s, %s, pb_%s_%s_doc},\n", obj->name,
|
||||
module, obj->name, obj->params ? "METH_VARARGS" : "METH_NOARGS",
|
||||
module, obj->name);
|
||||
}
|
||||
}
|
||||
appends(&bm, " {0},\n");
|
||||
appendf(&b, "\nstatic PyMethodDef pb_%s_methods[] = {\n", module);
|
||||
appendd(&b, bm, appendz(bm).i);
|
||||
appends(&b, "};\n");
|
||||
appendf(&b, "\n\
|
||||
static struct PyModuleDef pb_%s_module = {\n\
|
||||
PyModuleDef_HEAD_INIT,\n\
|
||||
\"%s\",\n\
|
||||
%s,\n\
|
||||
-1,\n\
|
||||
pb_%s_methods,\n\
|
||||
};\n\
|
||||
\n\
|
||||
PyMODINIT_FUNC\n\
|
||||
PyInit_%s(void)\n\
|
||||
{\n\
|
||||
return PyModule_Create(&pb_%s_module);\n\
|
||||
}\n\
|
||||
\n\
|
||||
__attribute__((__section__(\".rodata.pytab.1\")))\n\
|
||||
const struct _inittab _PyImport_Inittab_%s = {\n\
|
||||
\"%s\",\n\
|
||||
PyInit_%s,\n\
|
||||
};\n\
|
||||
",
|
||||
module, module,
|
||||
tok->file->javadown ? gc(xasprintf("pb_%s_doc", module)) : "0",
|
||||
module, module, module, module, module, module);
|
||||
CHECK_NE(-1, (fd = creat(path, 0644)));
|
||||
CHECK_NE(-1, xwrite(fd, b, appendz(b).i));
|
||||
CHECK_NE(-1, close(fd));
|
||||
free(bm);
|
||||
free(b);
|
||||
}
|
11
third_party/chibicc/strarray.c
vendored
11
third_party/chibicc/strarray.c
vendored
|
@ -1,14 +1,17 @@
|
|||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
void strarray_push(StringArray *arr, char *s) {
|
||||
size_t i;
|
||||
if (!arr->data) {
|
||||
arr->data = calloc(8, sizeof(char *));
|
||||
arr->capacity = 8;
|
||||
}
|
||||
if (arr->capacity == arr->len) {
|
||||
arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
|
||||
arr->capacity *= 2;
|
||||
for (int i = arr->len; i < arr->capacity; i++) arr->data[i] = NULL;
|
||||
if (arr->len + 1 == arr->capacity) {
|
||||
arr->capacity += arr->capacity >> 1;
|
||||
arr->data = realloc(arr->data, arr->capacity * sizeof(*arr->data));
|
||||
for (i = arr->len; i < arr->capacity; i++) {
|
||||
arr->data[i] = 0;
|
||||
}
|
||||
}
|
||||
arr->data[arr->len++] = s;
|
||||
}
|
||||
|
|
274
third_party/chibicc/tokenize.c
vendored
274
third_party/chibicc/tokenize.c
vendored
|
@ -1,7 +1,10 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
#include "third_party/chibicc/file.h"
|
||||
|
||||
#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, sizeof(OP) - 1))
|
||||
#include "third_party/chibicc/kw.h"
|
||||
|
||||
// Input file
|
||||
static File *current_file;
|
||||
|
@ -78,11 +81,6 @@ void warn_tok(Token *tok, char *fmt, ...) {
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
static int is_space(int c) {
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
|
||||
c == '\v';
|
||||
}
|
||||
|
||||
// Consumes the current token if it matches `op`.
|
||||
bool equal(Token *tok, char *op, size_t n) {
|
||||
return n == tok->len && !memcmp(tok->loc, op, tok->len);
|
||||
|
@ -122,11 +120,20 @@ static Token *new_token(TokenKind kind, char *start, char *end) {
|
|||
|
||||
// Read an identifier and returns the length of it.
|
||||
// If p does not point to a valid identifier, 0 is returned.
|
||||
static int read_ident(char *start) {
|
||||
noinline int read_ident(char *start) {
|
||||
uint32_t c;
|
||||
char *p = start;
|
||||
uint32_t c = decode_utf8(&p, p);
|
||||
if (('a' <= *p && *p <= 'z') || ('A' <= *p && *p <= 'Z') || *p == '_') {
|
||||
++p;
|
||||
} else {
|
||||
c = decode_utf8(&p, p);
|
||||
if (!is_ident1(c)) return 0;
|
||||
}
|
||||
for (;;) {
|
||||
if (('a' <= *p && *p <= 'z') || ('A' <= *p && *p <= 'Z') ||
|
||||
('0' <= *p && *p <= '9') || *p == '_') {
|
||||
++p;
|
||||
} else {
|
||||
char *q;
|
||||
c = decode_utf8(&q, p);
|
||||
if (!is_ident2(c)) {
|
||||
|
@ -135,6 +142,7 @@ static int read_ident(char *start) {
|
|||
p = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read a punctuator token from p and returns its length.
|
||||
int read_punct(char *p) {
|
||||
|
@ -142,46 +150,31 @@ int read_punct(char *p) {
|
|||
"<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=", "-=", "*=", "/=",
|
||||
"++", "--", "%=", "&=", "|=", "^=", "&&", "||", "<<", ">>", "##",
|
||||
};
|
||||
if (ispunct(*p)) {
|
||||
for (int i = 0; i < sizeof(kPunct) / sizeof(*kPunct); i++) {
|
||||
for (int j = 0;;) {
|
||||
if (p[j] != kPunct[i][j]) break;
|
||||
if (!kPunct[i][++j]) return j;
|
||||
}
|
||||
}
|
||||
return ispunct(*p) ? 1 : 0;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_keyword(Token *tok) {
|
||||
static HashMap map;
|
||||
if (map.capacity == 0) {
|
||||
static char *kw[] = {
|
||||
"return", "if", "else",
|
||||
"for", "while", "int",
|
||||
"sizeof", "char", "struct",
|
||||
"union", "short", "long",
|
||||
"void", "typedef", "_Bool",
|
||||
"enum", "static", "goto",
|
||||
"break", "continue", "switch",
|
||||
"case", "default", "extern",
|
||||
"_Alignof", "_Alignas", "do",
|
||||
"signed", "unsigned", "const",
|
||||
"volatile", "auto", "register",
|
||||
"restrict", "__restrict", "__restrict__",
|
||||
"_Noreturn", "float", "double",
|
||||
"typeof", "asm", "_Thread_local",
|
||||
"__thread", "_Atomic", "__attribute__",
|
||||
};
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
|
||||
hashmap_put(&map, kw[i], (void *)1);
|
||||
}
|
||||
}
|
||||
return hashmap_get2(&map, tok->loc, tok->len);
|
||||
unsigned char kw;
|
||||
kw = GetKw(tok->loc, tok->len);
|
||||
return kw && !(kw & -64);
|
||||
}
|
||||
|
||||
int read_escaped_char(char **new_pos, char *p) {
|
||||
int x;
|
||||
unsigned c;
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
// Read an octal number.
|
||||
unsigned c = *p++ - '0';
|
||||
c = *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
c = (c << 3) + (*p++ - '0');
|
||||
if ('0' <= *p && *p <= '7') c = (c << 3) + (*p++ - '0');
|
||||
|
@ -191,14 +184,15 @@ int read_escaped_char(char **new_pos, char *p) {
|
|||
}
|
||||
if (*p == 'x') {
|
||||
// Read a hexadecimal number.
|
||||
p++;
|
||||
if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence");
|
||||
unsigned c = 0;
|
||||
for (; isxdigit(*p); p++) {
|
||||
c = (c << 4) + hextoint(*p); /* TODO(jart): overflow here unicode_test */
|
||||
if ((++p, x = kHexToInt[*p++ & 255]) != -1) {
|
||||
for (c = x; (x = kHexToInt[*p & 255]) != -1; p++) {
|
||||
c = c << 4 | x;
|
||||
}
|
||||
*new_pos = p;
|
||||
return c;
|
||||
} else {
|
||||
error_at(p, "invalid hex escape sequence");
|
||||
}
|
||||
}
|
||||
*new_pos = p + 1;
|
||||
// Escape sequences are defined using themselves here. E.g.
|
||||
|
@ -330,14 +324,16 @@ static Token *read_char_literal(char *start, char *quote, Type *ty) {
|
|||
return tok;
|
||||
}
|
||||
|
||||
static bool convert_pp_int(Token *tok) {
|
||||
bool convert_pp_int(Token *tok) {
|
||||
char *p = tok->loc;
|
||||
// Read a binary, octal, decimal or hexadecimal number.
|
||||
int base = 10;
|
||||
if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) {
|
||||
if ((p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) &&
|
||||
kHexToInt[p[2] & 255] != -1) {
|
||||
p += 2;
|
||||
base = 16;
|
||||
} else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) {
|
||||
} else if ((p[0] == '0' && (p[1] == 'b' || p[1] == 'B')) &&
|
||||
(p[2] == '0' || p[2] == '1')) {
|
||||
p += 2;
|
||||
base = 2;
|
||||
} else if (*p == '0') {
|
||||
|
@ -347,24 +343,28 @@ static bool convert_pp_int(Token *tok) {
|
|||
// Read U, L or LL suffixes.
|
||||
bool l = false;
|
||||
bool u = false;
|
||||
if (LOOKINGAT(p, "LLU") || LOOKINGAT(p, "LLu") || LOOKINGAT(p, "llU") ||
|
||||
LOOKINGAT(p, "llu") || LOOKINGAT(p, "ULL") || LOOKINGAT(p, "Ull") ||
|
||||
LOOKINGAT(p, "uLL") || LOOKINGAT(p, "ull")) {
|
||||
int a, b, c;
|
||||
if ((a = kToLower[p[0] & 255]) && (a == 'l' || a == 'u')) {
|
||||
b = kToLower[p[1] & 255];
|
||||
c = b ? kToLower[p[2] & 255] : 0;
|
||||
if ((a == 'l' && b == 'l' && c == 'u') ||
|
||||
(a == 'u' && b == 'l' && c == 'l')) {
|
||||
p += 3;
|
||||
l = u = true;
|
||||
} else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) {
|
||||
} else if ((a == 'l' && b == 'u') || (a == 'u' && b == 'l')) {
|
||||
p += 2;
|
||||
l = u = true;
|
||||
} else if (LOOKINGAT(p, "LL") || LOOKINGAT(p, "ll")) {
|
||||
} else if (a == 'l' && b == 'l') {
|
||||
p += 2;
|
||||
l = true;
|
||||
} else if (*p == 'L' || *p == 'l') {
|
||||
p++;
|
||||
} else if (a == 'l') {
|
||||
p += 1;
|
||||
l = true;
|
||||
} else if (*p == 'U' || *p == 'u') {
|
||||
p++;
|
||||
} else if (a == 'u') {
|
||||
p += 1;
|
||||
u = true;
|
||||
}
|
||||
}
|
||||
if (p != tok->loc + tok->len) return false;
|
||||
// Infer a type.
|
||||
Type *ty;
|
||||
|
@ -462,24 +462,30 @@ Token *tokenize_string_literal(Token *tok, Type *basety) {
|
|||
|
||||
// Tokenize a given string and returns new tokens.
|
||||
Token *tokenize(File *file) {
|
||||
current_file = file;
|
||||
char *p = file->contents;
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
char *q, *p = file->contents;
|
||||
struct Javadown *javadown;
|
||||
current_file = file;
|
||||
at_bol = true;
|
||||
has_space = false;
|
||||
while (*p) {
|
||||
for (;;) {
|
||||
switch (*p) {
|
||||
case 0:
|
||||
cur = cur->next = new_token(TK_EOF, p, p);
|
||||
add_line_numbers(head.next);
|
||||
return head.next;
|
||||
case '/':
|
||||
// Skip line comments.
|
||||
if (LOOKINGAT(p, "//")) {
|
||||
if (p[1] == '/') {
|
||||
p += 2;
|
||||
while (*p != '\n') p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
// Javadoc-style markdown comments.
|
||||
if (LOOKINGAT(p, "/**") && p[3] != '/' && p[3] != '*') {
|
||||
char *q = strstr(p + 3, "*/");
|
||||
if (p[1] == '*' && p[2] == '*' && p[3] != '/' && p[3] != '*') {
|
||||
q = strstr(p + 3, "*/");
|
||||
if (!q) error_at(p, "unclosed javadown");
|
||||
javadown = ParseJavadown(p + 3, q - p - 3 - 2);
|
||||
if (javadown->isfileoverview) {
|
||||
|
@ -494,33 +500,51 @@ Token *tokenize(File *file) {
|
|||
continue;
|
||||
}
|
||||
// Skip block comments.
|
||||
if (LOOKINGAT(p, "/*")) {
|
||||
char *q = strstr(p + 2, "*/");
|
||||
if (p[1] == '*') {
|
||||
q = strstr(p + 2, "*/");
|
||||
if (!q) error_at(p, "unclosed block comment");
|
||||
p = q + 2;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
// Skip newline.
|
||||
if (*p == '\n') {
|
||||
p++;
|
||||
at_bol = true;
|
||||
has_space = false;
|
||||
continue;
|
||||
}
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\f':
|
||||
case '\v':
|
||||
// Skip whitespace characters.
|
||||
if (is_space(*p)) {
|
||||
p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
case '.':
|
||||
if (!isdigit(p[1])) break;
|
||||
/* fallthrough */
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
// Numeric literal
|
||||
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
|
||||
char *q = p++;
|
||||
q = p++;
|
||||
for (;;) {
|
||||
if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) {
|
||||
if (p[0] && p[1] &&
|
||||
(p[0] == 'e' || p[0] == 'E' || p[0] == 'p' || p[0] == 'P') &&
|
||||
(p[1] == '+' || p[1] == '-')) {
|
||||
p += 2;
|
||||
} else if (isalnum(*p) || *p == '.') {
|
||||
} else if (('0' <= *p && *p <= '9') || ('A' <= *p && *p <= 'Z') ||
|
||||
('a' <= *p && *p <= 'z') || *p == '.') {
|
||||
p++;
|
||||
} else {
|
||||
break;
|
||||
|
@ -528,63 +552,68 @@ Token *tokenize(File *file) {
|
|||
}
|
||||
cur = cur->next = new_token(TK_PP_NUM, q, p);
|
||||
continue;
|
||||
}
|
||||
case '"':
|
||||
// String literal
|
||||
if (*p == '"') {
|
||||
cur = cur->next = read_string_literal(p, p);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
case 'u':
|
||||
// UTF-8 string literal
|
||||
if (LOOKINGAT(p, "u8\"")) {
|
||||
if (p[1] == '8' && p[2] == '"') {
|
||||
cur = cur->next = read_string_literal(p, p + 2);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// UTF-16 string literal
|
||||
if (LOOKINGAT(p, "u\"")) {
|
||||
if (p[1] == '"') {
|
||||
cur = cur->next = read_utf16_string_literal(p, p + 1);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// Wide string literal
|
||||
if (LOOKINGAT(p, "L\"")) {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// UTF-32 string literal
|
||||
if (LOOKINGAT(p, "U\"")) {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// Character literal
|
||||
if (*p == '\'') {
|
||||
cur = cur->next = read_char_literal(p, p, ty_int);
|
||||
cur->val = (char)cur->val;
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// UTF-16 character literal
|
||||
if (LOOKINGAT(p, "u'")) {
|
||||
if (p[1] == '\'') {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_ushort);
|
||||
cur->val &= 0xffff;
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
// Wide string literal
|
||||
if (p[1] == '"') {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// Wide character literal
|
||||
if (LOOKINGAT(p, "L'")) {
|
||||
if (p[1] == '\'') {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_int);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
// Character literal
|
||||
cur = cur->next = read_char_literal(p, p, ty_int);
|
||||
cur->val = (char)cur->val;
|
||||
p += cur->len;
|
||||
continue;
|
||||
case 'U':
|
||||
// UTF-32 string literal
|
||||
if (p[1] == '"') {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
// UTF-32 character literal
|
||||
if (LOOKINGAT(p, "U'")) {
|
||||
if (p[1] == '\'') {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_uint);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Identifier or keyword
|
||||
int ident_len = read_ident(p);
|
||||
if (ident_len) {
|
||||
|
@ -601,9 +630,6 @@ Token *tokenize(File *file) {
|
|||
}
|
||||
error_at(p, "invalid token");
|
||||
}
|
||||
cur = cur->next = new_token(TK_EOF, p, p);
|
||||
add_line_numbers(head.next);
|
||||
return head.next;
|
||||
}
|
||||
|
||||
File **get_input_files(void) {
|
||||
|
@ -630,29 +656,56 @@ static uint32_t read_universal_char(char *p, int len) {
|
|||
|
||||
// Replace \u or \U escape sequences with corresponding UTF-8 bytes.
|
||||
static void convert_universal_chars(char *p) {
|
||||
uint32_t c;
|
||||
char *q = p;
|
||||
while (*p) {
|
||||
if (LOOKINGAT(p, "\\u")) {
|
||||
uint32_t c = read_universal_char(p + 2, 4);
|
||||
if (c) {
|
||||
for (;;) {
|
||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__chibicc__)
|
||||
typedef char xmm_u __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
if (!((uintptr_t)p & 15)) {
|
||||
xmm_t v;
|
||||
unsigned m;
|
||||
xmm_t z = {0};
|
||||
xmm_t s = {'\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\',
|
||||
'\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\'};
|
||||
for (;;) {
|
||||
v = *(const xmm_t *)p;
|
||||
m = __builtin_ia32_pmovmskb128((v == z) | (v == s));
|
||||
if (!m) {
|
||||
*(xmm_u *)q = v;
|
||||
p += 16;
|
||||
q += 16;
|
||||
} else {
|
||||
m = bsf(m);
|
||||
memmove(q, p, m);
|
||||
p += m;
|
||||
q += m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (p[0]) {
|
||||
if (p[0] == '\\') {
|
||||
if (p[1] == 'u') {
|
||||
if ((c = read_universal_char(p + 2, 4))) {
|
||||
p += 6;
|
||||
q += encode_utf8(q, c);
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
continue;
|
||||
}
|
||||
} else if (LOOKINGAT(p, "\\U")) {
|
||||
uint32_t c = read_universal_char(p + 2, 8);
|
||||
if (c) {
|
||||
} else if (p[1] == 'U') {
|
||||
if ((c = read_universal_char(p + 2, 8))) {
|
||||
p += 10;
|
||||
q += encode_utf8(q, c);
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
continue;
|
||||
}
|
||||
} else if (p[0] == '\\') {
|
||||
*q++ = *p++;
|
||||
}
|
||||
}
|
||||
*q++ = *p++;
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
|
@ -673,5 +726,6 @@ Token *tokenize_file(char *path) {
|
|||
input_files[file_no] = file;
|
||||
input_files[file_no + 1] = NULL;
|
||||
file_no++;
|
||||
/* ftrace_install(); */
|
||||
return tokenize(file);
|
||||
}
|
||||
|
|
6
third_party/chibicc/unicode.c
vendored
6
third_party/chibicc/unicode.c
vendored
|
@ -60,7 +60,7 @@ uint32_t decode_utf8(char **new_pos, char *p) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static bool in_range(uint32_t *range, uint32_t c) {
|
||||
static bool in_range(const uint32_t *range, uint32_t c) {
|
||||
for (int i = 0; range[i] != -1; i += 2) {
|
||||
if (range[i] <= c && c <= range[i + 1]) {
|
||||
return true;
|
||||
|
@ -80,7 +80,7 @@ static bool in_range(uint32_t *range, uint32_t c) {
|
|||
// 0x00BE-0x00C0 are allowed, while neither ⟘ (U+27D8) nor ' '
|
||||
// (U+3000, full-width space) are allowed because they are out of range.
|
||||
bool is_ident1(uint32_t c) {
|
||||
static uint32_t range[] = {
|
||||
static const uint32_t range[] = {
|
||||
0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
|
||||
0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
|
||||
0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
|
||||
|
@ -106,7 +106,7 @@ bool is_ident1(uint32_t c) {
|
|||
// Returns true if a given character is acceptable as a non-first
|
||||
// character of an identifier.
|
||||
bool is_ident2(uint32_t c) {
|
||||
static uint32_t range[] = {
|
||||
static const uint32_t range[] = {
|
||||
0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1,
|
||||
};
|
||||
if (is_ident1(c)) return true;
|
||||
|
|
6
third_party/dlmalloc/README.cosmo
vendored
6
third_party/dlmalloc/README.cosmo
vendored
|
@ -1,3 +1,9 @@
|
|||
ORIGIN
|
||||
|
||||
http://gee.cs.oswego.edu/
|
||||
|
||||
LOCAL CHANGES
|
||||
|
||||
Numerous local changes were made while vendoring Doug Lee's original
|
||||
dlmalloc sources. Those changes basically boil down to:
|
||||
|
||||
|
|
12
third_party/dlmalloc/bulk_free.c
vendored
12
third_party/dlmalloc/bulk_free.c
vendored
|
@ -3,13 +3,13 @@
|
|||
|
||||
/**
|
||||
* Frees and clears (sets to NULL) each non-null pointer in the given
|
||||
* array. This is likely to be faster than freeing them one-by-one. If
|
||||
* footers are used, pointers that have been allocated in different
|
||||
* mspaces are not freed or cleared, and the count of all such pointers
|
||||
* is returned. For large arrays of pointers with poor locality, it may
|
||||
* be worthwhile to sort this array before calling bulk_free.
|
||||
* array. This is twice as fast as freeing them one-by-one. If footers
|
||||
* are used, pointers that have been allocated in different mspaces are
|
||||
* not freed or cleared, and the count of all such pointers is returned.
|
||||
* For large arrays of pointers with poor locality, it may be worthwhile
|
||||
* to sort this array before calling bulk_free.
|
||||
*/
|
||||
size_t bulk_free(void *array[], size_t nelem) {
|
||||
size_t dlbulk_free(void *array[], size_t nelem) {
|
||||
/*
|
||||
* Try to free all pointers in the given array. Note: this could be
|
||||
* made faster, by delaying consolidation, at the price of disabling
|
||||
|
|
4
third_party/dlmalloc/dlcalloc.c
vendored
4
third_party/dlmalloc/dlcalloc.c
vendored
|
@ -6,6 +6,8 @@ void *dlcalloc(size_t n_elements, size_t elem_size) {
|
|||
size_t req;
|
||||
if (__builtin_mul_overflow(n_elements, elem_size, &req)) req = -1;
|
||||
mem = dlmalloc(req);
|
||||
if (mem != 0 && calloc_must_clear(mem2chunk(mem))) memset(mem, 0, req);
|
||||
if (mem != 0 && calloc_must_clear(mem2chunk(mem))) {
|
||||
bzero(mem, req);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
|
2
third_party/dlmalloc/dlindependent_calloc.c
vendored
2
third_party/dlmalloc/dlindependent_calloc.c
vendored
|
@ -66,7 +66,7 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts,
|
|||
assert(!is_mmapped(p));
|
||||
|
||||
if (opts & 0x2) { /* optionally clear the elements */
|
||||
memset((size_t *)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
|
||||
bzero((size_t *)mem, remainder_size - SIZE_T_SIZE - array_size);
|
||||
}
|
||||
|
||||
/* If not provided, allocate the pointer array as final part of chunk */
|
||||
|
|
8
third_party/dlmalloc/dlmalloc.c
vendored
8
third_party/dlmalloc/dlmalloc.c
vendored
|
@ -881,17 +881,13 @@ textstartup void dlmalloc_init(void) {
|
|||
|
||||
void *dlmemalign$impl(mstate m, size_t alignment, size_t bytes) {
|
||||
void *mem = 0;
|
||||
if (alignment < MIN_CHUNK_SIZE) { /* must be at least a minimum chunk size */
|
||||
alignment = MIN_CHUNK_SIZE; /* is 32 bytes on NexGen32e */
|
||||
}
|
||||
if ((alignment & (alignment - SIZE_T_ONE)) != 0) { /* Ensure a power of 2 */
|
||||
alignment = roundup2pow(alignment);
|
||||
}
|
||||
if (bytes >= MAX_REQUEST - alignment) {
|
||||
if (m != 0) { /* Test isn't needed but avoids compiler warning */
|
||||
enomem();
|
||||
}
|
||||
} else {
|
||||
/* alignment is 32+ bytes rounded up to nearest two power */
|
||||
alignment = 2ul << bsrl(MAX(MIN_CHUNK_SIZE, alignment) - 1);
|
||||
size_t nb = request2size(bytes);
|
||||
size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
|
||||
mem = dlmalloc_impl(req, false);
|
||||
|
|
4
third_party/dlmalloc/dlmalloc.internal.h
vendored
4
third_party/dlmalloc/dlmalloc.internal.h
vendored
|
@ -7,6 +7,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -854,7 +855,7 @@ extern struct MallocParams g_mparams;
|
|||
#define compute_bit2idx(X, I) \
|
||||
{ \
|
||||
unsigned int J; \
|
||||
J = __builtin_ctz(X); \
|
||||
J = bsf(X); \
|
||||
I = (bindex_t)J; \
|
||||
}
|
||||
|
||||
|
@ -1309,6 +1310,7 @@ struct MallocStats dlmalloc_stats(mstate) hidden;
|
|||
int dlmalloc_sys_trim(mstate, size_t) hidden;
|
||||
void dlmalloc_dispose_chunk(mstate, mchunkptr, size_t) hidden;
|
||||
mchunkptr dlmalloc_try_realloc_chunk(mstate, mchunkptr, size_t, int) hidden;
|
||||
size_t dlbulk_free(void *[], size_t) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
2
third_party/dlmalloc/dlmalloc_stats.c
vendored
2
third_party/dlmalloc/dlmalloc_stats.c
vendored
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
struct MallocStats dlmalloc_stats(mstate m) {
|
||||
struct MallocStats res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
bzero(&res, sizeof(res));
|
||||
ensure_initialization();
|
||||
if (!PREACTION(m)) {
|
||||
check_malloc_state(m);
|
||||
|
|
328
third_party/linenoise/linenoise.c
vendored
328
third_party/linenoise/linenoise.c
vendored
|
@ -14,6 +14,7 @@
|
|||
│ - Fix flickering │
|
||||
│ - Add UTF-8 editing │
|
||||
│ - Add CTRL-R search │
|
||||
│ - Support unlimited lines │
|
||||
│ - React to terminal resizing │
|
||||
│ - Don't generate .data section │
|
||||
│ - Support terminal flow control │
|
||||
|
@ -25,9 +26,9 @@
|
|||
│ - Fix corruption issues by using generalized parsing │
|
||||
│ - Implement nearly all GNU readline editing shortcuts │
|
||||
│ - Remove heavyweight dependencies like printf/sprintf │
|
||||
│ - Remove ISIG→^C→EAGAIN hack and catch signals properly │
|
||||
│ - Remove ISIG→^C→EAGAIN hack and use ephemeral handlers │
|
||||
│ - Support running on Windows in MinTTY or CMD.EXE on Win10+ │
|
||||
│ - Support diacratics, русский, Ελληνικά, 中国人, 한국인, 日本 │
|
||||
│ - Support diacratics, русский, Ελληνικά, 中国人, 日本語, 한국인 │
|
||||
│ │
|
||||
│ SHORTCUTS │
|
||||
│ │
|
||||
|
@ -47,6 +48,8 @@
|
|||
│ ALT-> END OF HISTORY │
|
||||
│ ALT-F FORWARD WORD │
|
||||
│ ALT-B BACKWARD WORD │
|
||||
│ CTRL-ALT-F FORWARD EXPR │
|
||||
│ CTRL-ALT-B BACKWARD EXPR │
|
||||
│ CTRL-K KILL LINE FORWARDS │
|
||||
│ CTRL-U KILL LINE BACKWARDS │
|
||||
│ ALT-H KILL WORD BACKWARDS │
|
||||
|
@ -60,11 +63,14 @@
|
|||
│ ALT-U UPPERCASE WORD │
|
||||
│ ALT-L LOWERCASE WORD │
|
||||
│ ALT-C CAPITALIZE WORD │
|
||||
│ CTRL-C INTERRUPT PROCESS │
|
||||
│ CTRL-Z SUSPEND PROCESS │
|
||||
│ CTRL-\ QUIT PROCESS │
|
||||
│ CTRL-S PAUSE OUTPUT │
|
||||
│ CTRL-Q UNPAUSE OUTPUT (IF PAUSED) │
|
||||
│ CTRL-Q ESCAPED INSERT │
|
||||
│ CTRL-SPACE SET MARK │
|
||||
│ CTRL-X CTRL-X GOTO MARK │
|
||||
│ CTRL-S PAUSE OUTPUT │
|
||||
│ CTRL-Q RESUME OUTPUT │
|
||||
│ CTRL-Z SUSPEND PROCESS │
|
||||
│ │
|
||||
│ EXAMPLE │
|
||||
│ │
|
||||
|
@ -125,6 +131,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -143,6 +150,7 @@
|
|||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
|
@ -200,9 +208,38 @@ struct linenoiseState {
|
|||
unsigned mark; /* saved cursor position */
|
||||
unsigned yi, yj; /* boundaries of last yank */
|
||||
char seq[2][16]; /* keystroke history for yanking code */
|
||||
char final; /* set to true on last update */
|
||||
char dirty; /* if an update was squashed */
|
||||
};
|
||||
|
||||
static const unsigned short kMirrorLeft[][2] = {
|
||||
{L'(', L')'}, {L'[', L']'}, {L'{', L'}'}, {L'⁅', L'⁆'},
|
||||
{L'⁽', L'⁾'}, {L'₍', L'₎'}, {L'⌈', L'⌉'}, {L'⌊', L'⌋'},
|
||||
{L'〈', L'〉'}, {L'❨', L'❩'}, {L'❪', L'❫'}, {L'❬', L'❭'},
|
||||
{L'❮', L'❯'}, {L'❰', L'❱'}, {L'❲', L'❳'}, {L'❴', L'❵'},
|
||||
{L'⟅', L'⟆'}, {L'⟦', L'⟧'}, {L'⟨', L'⟩'}, {L'⟪', L'⟫'},
|
||||
{L'⟬', L'⟭'}, {L'⟮', L'⟯'}, {L'⦃', L'⦄'}, {L'⦅', L'⦆'},
|
||||
{L'⦇', L'⦈'}, {L'⦉', L'⦊'}, {L'⦋', L'⦌'}, {L'⦍', L'⦐'},
|
||||
{L'⦏', L'⦎'}, {L'⦑', L'⦒'}, {L'⦓', L'⦔'}, {L'⦗', L'⦘'},
|
||||
{L'⧘', L'⧙'}, {L'⧚', L'⧛'}, {L'⧼', L'⧽'}, {L'﹙', L'﹚'},
|
||||
{L'﹛', L'﹜'}, {L'﹝', L'﹞'}, {L'(', L')'}, {L'[', L']'},
|
||||
{L'{', L'}'}, {L'「', L'」'},
|
||||
};
|
||||
|
||||
static const unsigned short kMirrorRight[][2] = {
|
||||
{L')', L'('}, {L']', L'['}, {L'}', L'{'}, {L'⁆', L'⁅'},
|
||||
{L'⁾', L'⁽'}, {L'₎', L'₍'}, {L'⌉', L'⌈'}, {L'⌋', L'⌊'},
|
||||
{L'〉', L'〈'}, {L'❩', L'❨'}, {L'❫', L'❪'}, {L'❭', L'❬'},
|
||||
{L'❯', L'❮'}, {L'❱', L'❰'}, {L'❳', L'❲'}, {L'❵', L'❴'},
|
||||
{L'⟆', L'⟅'}, {L'⟧', L'⟦'}, {L'⟩', L'⟨'}, {L'⟫', L'⟪'},
|
||||
{L'⟭', L'⟬'}, {L'⟯', L'⟮'}, {L'⦄', L'⦃'}, {L'⦆', L'⦅'},
|
||||
{L'⦈', L'⦇'}, {L'⦊', L'⦉'}, {L'⦌', L'⦋'}, {L'⦎', L'⦏'},
|
||||
{L'⦐', L'⦍'}, {L'⦒', L'⦑'}, {L'⦔', L'⦓'}, {L'⦘', L'⦗'},
|
||||
{L'⧙', L'⧘'}, {L'⧛', L'⧚'}, {L'⧽', L'⧼'}, {L'﹚', L'﹙'},
|
||||
{L'﹜', L'﹛'}, {L'﹞', L'﹝'}, {L')', L'('}, {L']', L'['},
|
||||
{L'}', L'{'}, {L'」', L'「'},
|
||||
};
|
||||
|
||||
static const char *const kUnsupported[] = {"dumb", "cons25", "emacs"};
|
||||
|
||||
static int gotint;
|
||||
|
@ -210,6 +247,7 @@ static int gotcont;
|
|||
static int gotwinch;
|
||||
static char rawmode;
|
||||
static char maskmode;
|
||||
static char ispaused;
|
||||
static char iscapital;
|
||||
static int historylen;
|
||||
static struct linenoiseRing ring;
|
||||
|
@ -226,6 +264,35 @@ static linenoiseCompletionCallback *completionCallback;
|
|||
static void linenoiseAtExit(void);
|
||||
static void linenoiseRefreshLine(struct linenoiseState *);
|
||||
|
||||
static unsigned GetMirror(const unsigned short A[][2], size_t n, unsigned c) {
|
||||
int l, m, r;
|
||||
l = 0;
|
||||
r = n - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
if (A[m][0] < c) {
|
||||
l = m + 1;
|
||||
} else if (A[m][0] > c) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return A[m][1];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned GetMirrorLeft(unsigned c) {
|
||||
return GetMirror(kMirrorRight, ARRAYLEN(kMirrorRight), c);
|
||||
}
|
||||
|
||||
static unsigned GetMirrorRight(unsigned c) {
|
||||
return GetMirror(kMirrorLeft, ARRAYLEN(kMirrorLeft), c);
|
||||
}
|
||||
|
||||
static int isxseparator(wint_t c) {
|
||||
return iswseparator(c) && !GetMirrorLeft(c) && !GetMirrorRight(c);
|
||||
}
|
||||
|
||||
static int notwseparator(wint_t c) {
|
||||
return !iswseparator(c);
|
||||
}
|
||||
|
@ -586,13 +653,20 @@ static int linenoiseIsUnsupportedTerm(void) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static void linenoiseUnpause(int fd) {
|
||||
if (ispaused) {
|
||||
tcflow(fd, TCOON);
|
||||
ispaused = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int enableRawMode(int fd) {
|
||||
struct termios raw;
|
||||
struct sigaction sa;
|
||||
if (tcgetattr(fd, &orig_termios) != -1) {
|
||||
raw = orig_termios;
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP);
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
raw.c_oflag &= ~OPOST;
|
||||
raw.c_iflag |= IUTF8;
|
||||
raw.c_cflag |= CS8;
|
||||
|
@ -617,6 +691,7 @@ static int enableRawMode(int fd) {
|
|||
|
||||
void linenoiseDisableRawMode(void) {
|
||||
if (rawmode != -1) {
|
||||
linenoiseUnpause(rawmode);
|
||||
sigaction(SIGCONT, &orig_cont, 0);
|
||||
sigaction(SIGWINCH, &orig_winch, 0);
|
||||
tcsetattr(rawmode, TCSAFLUSH, &orig_termios);
|
||||
|
@ -633,6 +708,9 @@ static int linenoiseWrite(int fd, const void *p, size_t n) {
|
|||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
if (ispaused) {
|
||||
return 0;
|
||||
}
|
||||
rc = write(fd, p, n);
|
||||
if (rc == -1 && errno == EINTR) {
|
||||
continue;
|
||||
|
@ -982,11 +1060,88 @@ static char *linenoiseRefreshHints(struct linenoiseState *l) {
|
|||
return ab.b;
|
||||
}
|
||||
|
||||
static size_t Forward(struct linenoiseState *l, size_t pos) {
|
||||
return pos + GetUtf8(l->buf + pos, l->len - pos).n;
|
||||
}
|
||||
|
||||
static size_t Backward(struct linenoiseState *l, size_t pos) {
|
||||
if (pos) {
|
||||
do --pos;
|
||||
while (pos && (l->buf[pos] & 0300) == 0200);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int linenoiseMirrorLeft(struct linenoiseState *l, unsigned res[2]) {
|
||||
unsigned c, pos, left, right, depth, index;
|
||||
if ((pos = Backward(l, l->pos))) {
|
||||
right = GetUtf8(l->buf + pos, l->len - pos).c;
|
||||
if ((left = GetMirrorLeft(right))) {
|
||||
depth = 0;
|
||||
index = pos;
|
||||
do {
|
||||
pos = Backward(l, pos);
|
||||
c = GetUtf8(l->buf + pos, l->len - pos).c;
|
||||
if (c == right) {
|
||||
++depth;
|
||||
} else if (c == left) {
|
||||
if (depth) {
|
||||
--depth;
|
||||
} else {
|
||||
res[0] = pos;
|
||||
res[1] = index;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (pos);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int linenoiseMirrorRight(struct linenoiseState *l, unsigned res[2]) {
|
||||
struct rune rune;
|
||||
unsigned pos, left, right, depth, index;
|
||||
pos = l->pos;
|
||||
rune = GetUtf8(l->buf + pos, l->len - pos);
|
||||
left = rune.c;
|
||||
if ((right = GetMirrorRight(left))) {
|
||||
depth = 0;
|
||||
index = pos;
|
||||
do {
|
||||
pos += rune.n;
|
||||
rune = GetUtf8(l->buf + pos, l->len - pos);
|
||||
if (rune.c == left) {
|
||||
++depth;
|
||||
} else if (rune.c == right) {
|
||||
if (depth) {
|
||||
--depth;
|
||||
} else {
|
||||
res[0] = index;
|
||||
res[1] = pos;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (pos + rune.n < l->len);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int linenoiseMirror(struct linenoiseState *l, unsigned res[2]) {
|
||||
int rc;
|
||||
rc = linenoiseMirrorLeft(l, res);
|
||||
if (rc == -1) rc = linenoiseMirrorRight(l, res);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void linenoiseRefreshLineImpl(struct linenoiseState *l, int force) {
|
||||
char *hint;
|
||||
char flipit;
|
||||
char hasflip;
|
||||
char haswides;
|
||||
struct abuf ab;
|
||||
struct rune rune;
|
||||
unsigned flip[2];
|
||||
const char *p, *buf;
|
||||
struct winsize oldsize;
|
||||
int i, x, y, t, xn, yn, cx, cy, tn, resized;
|
||||
|
@ -995,6 +1150,13 @@ static void linenoiseRefreshLineImpl(struct linenoiseState *l, int force) {
|
|||
/*
|
||||
* synchonize the i/o state
|
||||
*/
|
||||
if (ispaused) {
|
||||
if (force) {
|
||||
linenoiseUnpause(l->ofd);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!force && HasPendingInput(l->ifd)) {
|
||||
l->dirty = 1;
|
||||
return;
|
||||
|
@ -1004,6 +1166,7 @@ static void linenoiseRefreshLineImpl(struct linenoiseState *l, int force) {
|
|||
gotwinch = 0;
|
||||
l->ws = GetTerminalSize(l->ws, l->ifd, l->ofd);
|
||||
}
|
||||
hasflip = !l->final && !linenoiseMirror(l, flip);
|
||||
|
||||
StartOver:
|
||||
fd = l->ofd;
|
||||
|
@ -1090,13 +1253,16 @@ StartOver:
|
|||
if (maskmode) {
|
||||
abAppendw(&ab, '*');
|
||||
} else {
|
||||
flipit = hasflip && (i == flip[0] || i == flip[1]);
|
||||
if (flipit) abAppendw(&ab, READ32LE("\033[1m"));
|
||||
abAppendw(&ab, tpenc(rune.c));
|
||||
if (flipit) abAppendw(&ab, READ64LE("\033[22m\0\0"));
|
||||
}
|
||||
t = wcwidth(rune.c);
|
||||
t = MAX(0, t);
|
||||
x += t;
|
||||
}
|
||||
if ((hint = linenoiseRefreshHints(l))) {
|
||||
if (!l->final && (hint = linenoiseRefreshHints(l))) {
|
||||
if (GetMonospaceWidth(hint, strlen(hint), 0) < xn - x) {
|
||||
if (cx < 0) {
|
||||
cx = x;
|
||||
|
@ -1203,18 +1369,6 @@ static void linenoiseEditRefresh(struct linenoiseState *l) {
|
|||
linenoiseRefreshLine(l);
|
||||
}
|
||||
|
||||
static size_t Forward(struct linenoiseState *l, size_t pos) {
|
||||
return pos + GetUtf8(l->buf + pos, l->len - pos).n;
|
||||
}
|
||||
|
||||
static size_t Backward(struct linenoiseState *l, size_t pos) {
|
||||
if (pos) {
|
||||
do --pos;
|
||||
while (pos && (l->buf[pos] & 0300) == 0200);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static size_t Backwards(struct linenoiseState *l, size_t pos,
|
||||
int pred(wint_t)) {
|
||||
size_t i;
|
||||
|
@ -1296,6 +1450,28 @@ static void linenoiseEditRightWord(struct linenoiseState *l) {
|
|||
linenoiseRefreshLine(l);
|
||||
}
|
||||
|
||||
static void linenoiseEditLeftExpr(struct linenoiseState *l) {
|
||||
unsigned mark[2];
|
||||
l->pos = Backwards(l, l->pos, isxseparator);
|
||||
if (!linenoiseMirrorLeft(l, mark)) {
|
||||
l->pos = mark[0];
|
||||
} else {
|
||||
l->pos = Backwards(l, l->pos, notwseparator);
|
||||
}
|
||||
linenoiseRefreshLine(l);
|
||||
}
|
||||
|
||||
static void linenoiseEditRightExpr(struct linenoiseState *l) {
|
||||
unsigned mark[2];
|
||||
l->pos = Forwards(l, l->pos, isxseparator);
|
||||
if (!linenoiseMirrorRight(l, mark)) {
|
||||
l->pos = Forward(l, mark[1]);
|
||||
} else {
|
||||
l->pos = Forwards(l, l->pos, notwseparator);
|
||||
}
|
||||
linenoiseRefreshLine(l);
|
||||
}
|
||||
|
||||
static void linenoiseEditDelete(struct linenoiseState *l) {
|
||||
size_t i;
|
||||
if (l->pos == l->len) return;
|
||||
|
@ -1484,6 +1660,76 @@ static void linenoiseEditGoto(struct linenoiseState *l) {
|
|||
linenoiseRefreshLine(l);
|
||||
}
|
||||
|
||||
static size_t linenoiseEscape(char *d, const char *s, size_t n) {
|
||||
char *p;
|
||||
size_t i;
|
||||
unsigned c, w, l;
|
||||
for (p = d, l = i = 0; i < n; ++i) {
|
||||
switch ((c = s[i] & 255)) {
|
||||
CASE('\a', w = READ16LE("\\a"));
|
||||
CASE('\b', w = READ16LE("\\b"));
|
||||
CASE('\t', w = READ16LE("\\t"));
|
||||
CASE('\n', w = READ16LE("\\n"));
|
||||
CASE('\v', w = READ16LE("\\v"));
|
||||
CASE('\f', w = READ16LE("\\f"));
|
||||
CASE('\r', w = READ16LE("\\r"));
|
||||
CASE('"', w = READ16LE("\\\""));
|
||||
CASE('\'', w = READ16LE("\\\'"));
|
||||
CASE('\\', w = READ16LE("\\\\"));
|
||||
default:
|
||||
if ((0x00 <= c && c <= 0x1F) || c == 0x7F || (c == '?' && l == '?')) {
|
||||
w = READ16LE("\\x");
|
||||
w |= "0123456789abcdef"[(c & 0xF0) >> 4] << 020;
|
||||
w |= "0123456789abcdef"[(c & 0x0F) >> 0] << 030;
|
||||
} else {
|
||||
w = c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
WRITE32LE(p, w);
|
||||
p += (bsr(w) >> 3) + 1;
|
||||
l = w;
|
||||
}
|
||||
return p - d;
|
||||
}
|
||||
|
||||
static void linenoiseEditInsertEscape(struct linenoiseState *l) {
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
char seq[16];
|
||||
char esc[sizeof(seq) * 4];
|
||||
if ((n = linenoiseRead(l->ifd, seq, sizeof(seq), l)) > 0) {
|
||||
m = linenoiseEscape(esc, seq, n);
|
||||
linenoiseEditInsert(l, esc, m);
|
||||
}
|
||||
}
|
||||
|
||||
static void linenoiseEditInterrupt(struct linenoiseState *l) {
|
||||
gotint = SIGINT;
|
||||
}
|
||||
|
||||
static void linenoiseEditQuit(struct linenoiseState *l) {
|
||||
gotint = SIGQUIT;
|
||||
}
|
||||
|
||||
static void linenoiseEditSuspend(struct linenoiseState *l) {
|
||||
raise(SIGSTOP);
|
||||
}
|
||||
|
||||
static void linenoiseEditPause(struct linenoiseState *l) {
|
||||
tcflow(l->ofd, TCOOFF);
|
||||
ispaused = 1;
|
||||
}
|
||||
|
||||
static void linenoiseEditCtrlq(struct linenoiseState *l) {
|
||||
if (ispaused) {
|
||||
linenoiseUnpause(l->ofd);
|
||||
linenoiseRefreshLineForce(l);
|
||||
} else {
|
||||
linenoiseEditInsertEscape(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs linenoise engine.
|
||||
*
|
||||
|
@ -1502,7 +1748,6 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
size_t nread;
|
||||
char *p, seq[16];
|
||||
struct linenoiseState l;
|
||||
linenoiseHintsCallback *hc;
|
||||
bzero(&l, sizeof(l));
|
||||
if (!(l.buf = malloc((l.buflen = 32)))) return -1;
|
||||
l.buf[0] = 0;
|
||||
|
@ -1512,7 +1757,7 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
l.ws = GetTerminalSize(l.ws, l.ifd, l.ofd);
|
||||
linenoiseHistoryAdd("");
|
||||
linenoiseWriteStr(l.ofd, l.prompt);
|
||||
while (1) {
|
||||
for (;;) {
|
||||
if (l.dirty) linenoiseRefreshLineForce(&l);
|
||||
rc = linenoiseRead(l.ifd, seq, sizeof(seq), &l);
|
||||
if (rc > 0) {
|
||||
|
@ -1531,8 +1776,7 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
seq[0] = '\r';
|
||||
seq[1] = 0;
|
||||
} else {
|
||||
historylen--;
|
||||
free(history[historylen]);
|
||||
free(history[--historylen]);
|
||||
history[historylen] = 0;
|
||||
free(l.buf);
|
||||
return -1;
|
||||
|
@ -1545,11 +1789,16 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
CASE(CTRL('B'), linenoiseEditLeft(&l));
|
||||
CASE(CTRL('@'), linenoiseEditMark(&l));
|
||||
CASE(CTRL('Y'), linenoiseEditYank(&l));
|
||||
CASE(CTRL('Q'), linenoiseEditCtrlq(&l));
|
||||
CASE(CTRL('F'), linenoiseEditRight(&l));
|
||||
CASE(CTRL('\\'), linenoiseEditQuit(&l));
|
||||
CASE(CTRL('S'), linenoiseEditPause(&l));
|
||||
CASE(CTRL('?'), linenoiseEditRubout(&l));
|
||||
CASE(CTRL('H'), linenoiseEditRubout(&l));
|
||||
CASE(CTRL('L'), linenoiseEditRefresh(&l));
|
||||
CASE(CTRL('Z'), linenoiseEditSuspend(&l));
|
||||
CASE(CTRL('U'), linenoiseEditKillLeft(&l));
|
||||
CASE(CTRL('C'), linenoiseEditInterrupt(&l));
|
||||
CASE(CTRL('T'), linenoiseEditTranspose(&l));
|
||||
CASE(CTRL('K'), linenoiseEditKillRight(&l));
|
||||
CASE(CTRL('W'), linenoiseEditRuboutWord(&l));
|
||||
|
@ -1569,13 +1818,11 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
}
|
||||
break;
|
||||
case '\r':
|
||||
l.final = 1;
|
||||
free(history[--historylen]);
|
||||
history[historylen] = 0;
|
||||
linenoiseEditEnd(&l);
|
||||
hc = hintsCallback;
|
||||
hintsCallback = 0;
|
||||
linenoiseRefreshLineForce(&l);
|
||||
hintsCallback = hc;
|
||||
if ((p = realloc(l.buf, l.len + 1))) l.buf = p;
|
||||
*obuf = l.buf;
|
||||
return l.len;
|
||||
|
@ -1594,6 +1841,8 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
CASE('u', linenoiseEditUppercaseWord(&l));
|
||||
CASE('c', linenoiseEditCapitalizeWord(&l));
|
||||
CASE('t', linenoiseEditTransposeWords(&l));
|
||||
CASE(CTRL('B'), linenoiseEditLeftExpr(&l));
|
||||
CASE(CTRL('F'), linenoiseEditRightExpr(&l));
|
||||
CASE(CTRL('H'), linenoiseEditRuboutWord(&l));
|
||||
case '[':
|
||||
if (nread < 3) break;
|
||||
|
@ -1634,6 +1883,31 @@ static ssize_t linenoiseEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 033:
|
||||
if (nread < 3) break;
|
||||
switch (seq[2]) {
|
||||
case '[':
|
||||
if (nread < 4) break;
|
||||
switch (seq[3]) {
|
||||
CASE('C', linenoiseEditRightExpr(&l)); /* \e\e[C alt-right */
|
||||
CASE('D', linenoiseEditLeftExpr(&l)); /* \e\e[D alt-left */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
if (nread < 4) break;
|
||||
switch (seq[3]) {
|
||||
CASE('C', linenoiseEditRightExpr(&l)); /* \e\eOC alt-right */
|
||||
CASE('D', linenoiseEditLeftExpr(&l)); /* \e\eOD alt-left */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
52
third_party/python/Include/ceval.h
vendored
52
third_party/python/Include/ceval.h
vendored
|
@ -2,7 +2,6 @@
|
|||
#define Py_CEVAL_H
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "third_party/python/Include/object.h"
|
||||
#include "third_party/python/Include/pyerrors.h"
|
||||
#include "third_party/python/Include/pystate.h"
|
||||
|
@ -102,31 +101,34 @@ int Py_GetRecursionLimit(void);
|
|||
#define _Py_MakeEndRecCheck(x) \
|
||||
(--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit))
|
||||
|
||||
int _Py_CheckRecursiveCall(const char *);
|
||||
int Py_EnterRecursiveCall(const char *);
|
||||
void Py_LeaveRecursiveCall(void);
|
||||
|
||||
#ifndef Py_LIMITED_API
|
||||
extern int _Py_CheckRecursionLimit;
|
||||
|
||||
forceinline int Py_EnterRecursiveCall(const char *where) {
|
||||
const char *rsp, *bot;
|
||||
if (!IsTiny()) {
|
||||
if (IsModeDbg()) {
|
||||
PyThreadState_GET()->recursion_depth++;
|
||||
return _Py_CheckRecursiveCall(where);
|
||||
} else {
|
||||
rsp = __builtin_frame_address(0);
|
||||
asm(".weak\tape_stack_vaddr\n\t"
|
||||
"movabs\t$ape_stack_vaddr+32768,%0" : "=r"(bot));
|
||||
if (UNLIKELY(rsp < bot)) {
|
||||
PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
forceinline void Py_LeaveRecursiveCall(void) {
|
||||
PyThreadState_GET()->recursion_depth--;
|
||||
}
|
||||
int _Py_CheckRecursiveCall(const char *);
|
||||
#define Py_LeaveRecursiveCall() PyThreadState_GET()->recursion_depth--
|
||||
#define Py_EnterRecursiveCall(where) \
|
||||
({ \
|
||||
int rc = 0; \
|
||||
const char *rsp, *bot; \
|
||||
if (!IsTiny()) { \
|
||||
if (IsModeDbg()) { \
|
||||
PyThreadState_GET()->recursion_depth++; \
|
||||
rc = _Py_CheckRecursiveCall(where); \
|
||||
} else { \
|
||||
rsp = __builtin_frame_address(0); \
|
||||
asm(".weak\tape_stack_vaddr\n\t" \
|
||||
"movabs\t$ape_stack_vaddr+32768,%0" : "=r"(bot)); \
|
||||
if (UNLIKELY(rsp < bot)) { \
|
||||
PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where); \
|
||||
rc = -1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
rc; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define Py_ALLOW_RECURSION \
|
||||
do { \
|
||||
|
|
62
third_party/python/Include/pyctype.h
vendored
62
third_party/python/Include/pyctype.h
vendored
|
@ -6,36 +6,50 @@
|
|||
#define Py_TOLOWER(c) kToLower[255 & (c)]
|
||||
#define Py_TOUPPER(c) kToUpper[255 & (c)]
|
||||
|
||||
forceinline bool Py_ISDIGIT(unsigned char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
#define Py_ISDIGIT(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
'0' <= c_&& c_ <= '9'; \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISLOWER(unsigned char c) {
|
||||
return 'a' <= c && c <= 'z';
|
||||
}
|
||||
#define Py_ISLOWER(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
'a' <= c_&& c_ <= 'z'; \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISUPPER(unsigned char c) {
|
||||
return 'A' <= c && c <= 'Z';
|
||||
}
|
||||
#define Py_ISUPPER(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
'A' <= c_&& c_ <= 'Z'; \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISALPHA(unsigned char c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
#define Py_ISALPHA(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
('A' <= c_ && c_ <= 'Z') || ('a' <= c_ && c_ <= 'z'); \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISALNUM(unsigned char c) {
|
||||
return ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') ||
|
||||
('a' <= c && c <= 'z');
|
||||
}
|
||||
#define Py_ISALNUM(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
(('0' <= c_ && c_ <= '9') || ('A' <= c_ && c_ <= 'Z') || \
|
||||
('a' <= c_ && c_ <= 'z')); \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISSPACE(unsigned char c) {
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
|
||||
c == '\v';
|
||||
}
|
||||
#define Py_ISSPACE(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
(c_ == ' ' || c_ == '\t' || c_ == '\r' || c_ == '\n' || c_ == '\f' || \
|
||||
c_ == '\v'); \
|
||||
})
|
||||
|
||||
forceinline bool Py_ISXDIGIT(unsigned char c) {
|
||||
return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') ||
|
||||
('a' <= c && c <= 'f');
|
||||
}
|
||||
#define Py_ISXDIGIT(C) \
|
||||
({ \
|
||||
unsigned char c_ = (C); \
|
||||
(('0' <= c_ && c_ <= '9') || ('A' <= c_ && c_ <= 'F') || \
|
||||
('a' <= c_ && c_ <= 'f')); \
|
||||
})
|
||||
|
||||
#endif /* !PYCTYPE_H */
|
||||
#endif /* !Py_LIMITED_API */
|
||||
|
|
1
third_party/python/Lib/test/test_class.py
vendored
1
third_party/python/Lib/test/test_class.py
vendored
|
@ -490,6 +490,7 @@ class ClassTests(unittest.TestCase):
|
|||
|
||||
self.assertRaises(TypeError, hash, C2())
|
||||
|
||||
@unittest.skipIf(cosmo.MODE == 'tiny', "no stack awareness in tiny mode")
|
||||
def testSFBug532646(self):
|
||||
# Test for SF bug 532646
|
||||
|
||||
|
|
4
third_party/python/Lib/test/test_codecs.py
vendored
4
third_party/python/Lib/test/test_codecs.py
vendored
|
@ -1331,7 +1331,7 @@ class EscapeDecodeTest(unittest.TestCase):
|
|||
check(br"[\x410]", b"[A0]")
|
||||
for i in range(97, 123):
|
||||
b = bytes([i])
|
||||
if b not in b'abfnrtvx':
|
||||
if b not in b'abfnrtvxe': # [jart] support \e
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
check(b"\\" + b, b"\\" + b)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
|
@ -2603,7 +2603,7 @@ class UnicodeEscapeTest(unittest.TestCase):
|
|||
check(br"\U0001d120", "\U0001d120")
|
||||
for i in range(97, 123):
|
||||
b = bytes([i])
|
||||
if b not in b'abfnrtuvx':
|
||||
if b not in b'abfnrtuvxe': # [jart] support \e
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
check(b"\\" + b, "\\" + chr(i))
|
||||
if b.upper() not in b'UN':
|
||||
|
|
8
third_party/python/Lib/test/test_compile.py
vendored
8
third_party/python/Lib/test/test_compile.py
vendored
|
@ -163,8 +163,12 @@ if 1:
|
|||
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
|
||||
"080000000000000", "000000000000009", "000000000000008",
|
||||
"0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
|
||||
"0b101j2", "0o153j2", "0b100e1", "0o777e1", "0777",
|
||||
"000777", "000000000000007"]:
|
||||
"0b101j2", "0o153j2", "0b100e1", "0o777e1",
|
||||
# [jart] restore octal
|
||||
# "0777",
|
||||
# "000777",
|
||||
# "000000000000007",
|
||||
]:
|
||||
self.assertRaises(SyntaxError, eval, arg)
|
||||
|
||||
self.assertEqual(eval("0xff"), 255)
|
||||
|
|
2
third_party/python/Lib/test/test_fileio.py
vendored
2
third_party/python/Lib/test/test_fileio.py
vendored
|
@ -177,7 +177,7 @@ class AutoFileTests:
|
|||
finally:
|
||||
os.close(fd)
|
||||
|
||||
# @unittest.skipUnless(cosmo.MODE == "dbg", "disabled recursion checking")
|
||||
@unittest.skipIf(cosmo.MODE == 'tiny', "no stack awareness in tiny mode")
|
||||
def testRecursiveRepr(self):
|
||||
# Issue #25455
|
||||
with swap_attr(self.f, 'name', self.f):
|
||||
|
|
1
third_party/python/Lib/test/test_plistlib.py
vendored
1
third_party/python/Lib/test/test_plistlib.py
vendored
|
@ -814,6 +814,7 @@ class TestBinaryPlistlib(unittest.TestCase):
|
|||
b = plistlib.loads(plistlib.dumps(a, fmt=plistlib.FMT_BINARY))
|
||||
self.assertIs(b['x'], b)
|
||||
|
||||
@unittest.skipIf(cosmo.MODE == 'tiny', "no stack awareness in tiny mode")
|
||||
def test_deep_nesting(self):
|
||||
for N in [300, 100000]:
|
||||
chunks = [b'\xa1' + (i + 1).to_bytes(4, 'big') for i in range(N)]
|
||||
|
|
4
third_party/python/Lib/test/test_scratch.py
vendored
4
third_party/python/Lib/test/test_scratch.py
vendored
|
@ -8,10 +8,10 @@ exit1 = cosmo.exit1
|
|||
|
||||
class BooTest(unittest.TestCase):
|
||||
def test_boo(self):
|
||||
pass
|
||||
# cosmo.ftrace()
|
||||
# chr(33)
|
||||
# eval('0')
|
||||
# exit1()
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
│ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "third_party/python/Include/abstract.h"
|
||||
#include "third_party/python/Include/boolobject.h"
|
||||
#include "third_party/python/Include/complexobject.h"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue