diff --git a/Makefile b/Makefile index 35495a608..19c6794f0 100644 --- a/Makefile +++ b/Makefile @@ -303,6 +303,7 @@ COSMOPOLITAN_HEADERS = \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ + THIRD_PARTY_ZLIB \ THIRD_PARTY_REGEX o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_OBJS))) @@ -312,6 +313,10 @@ o/cosmopolitan.h: \ $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) @ACTION=ROLLUP TARGET=$@ build/do $^ >$@ +o/cosmopolitan.html: \ + o//third_party/chibicc/chibicc.com.dbg + o//third_party/chibicc/chibicc.com.dbg -J -fno-common -include libc/integral/normalize.inc -o $@ $(filter %.c,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) + # UNSPECIFIED PREREQUISITES TUTORIAL # # A build rule must exist for all files that make needs to consider in diff --git a/ape/config.h b/ape/config.h index b988bdec3..440a65285 100644 --- a/ape/config.h +++ b/ape/config.h @@ -3,11 +3,7 @@ #include "ape/relocations.h" #include "libc/macros.h" -/** - * @fileverview αcτµαlly pδrταblε εxεcµταblε configuration. - */ - -/** +/* * Post-Initialization Read-Only Code Size Threshold. * * An executable needs to have at least this much code, before the @@ -22,9 +18,6 @@ #endif #endif -/** - * PC Standard I/O Configuration. - */ #ifndef METAL_STDIN #define METAL_STDIN COM1 #endif @@ -35,11 +28,6 @@ #define METAL_STDERR COM1 #endif -/** - * PC Display Configuration (MDA/CGA) - * @see www.lammertbies.nl/comm/info/serial-uart.html - * @see ape/lib/vidya.internal.h - */ #ifndef VIDYA_MODE #define VIDYA_MODE VIDYA_MODE_CGA #endif @@ -66,10 +54,6 @@ #define X87_DEFAULT X87_NORMAL #endif -/** - * Serial Line Configuration (8250 UART 16550) - * @see ape/lib/uart.h - */ #ifndef UART_BAUD_RATE #define UART_BAUD_RATE 9600 /* bits per second ∈ [50,115200] */ #endif @@ -93,9 +77,6 @@ #define UART_CONF_LCR 0b01000011 #endif -/** - * eXtreme Low Memory. - */ #define XLM(VAR) (XLM_BASE_REAL + XLM_##VAR) #define XLMV(VAR) (__xlm + XLM_##VAR) #define XLM_BASE_REAL 0x1000 diff --git a/ape/relocations.h b/ape/relocations.h index 6dc3ad381..1500d2b64 100644 --- a/ape/relocations.h +++ b/ape/relocations.h @@ -19,23 +19,23 @@ #define IMAGE_BASE_PHYSICAL 0x100000 #endif +#ifndef REAL_SCRATCH_AREA /** * Location of anything goes memory for real mode. * * The MBR won't load program content beyond this address, so we have * room for buffers, page tables, etc. before we reach the stack frame. */ -#ifndef REAL_SCRATCH_AREA #define REAL_SCRATCH_AREA 0x40000 #endif +#ifndef REAL_STACK_FRAME /** * Location of real mode 64kb stack frame. * * This address was chosen because memory beyond 0x80000 can't be * accessed safely without consulting e820. */ -#ifndef REAL_STACK_FRAME #define REAL_STACK_FRAME 0x70000 #endif diff --git a/libc/alg/memmem.c b/libc/alg/memmem.c index 666a5faf3..196cc863c 100644 --- a/libc/alg/memmem.c +++ b/libc/alg/memmem.c @@ -21,12 +21,8 @@ #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/str/str.h" -/* clang-format off */ -static void KnuthMorrisPrattInit(m, T, W) - ssize_t m, T[m + 1]; - const char W[m]; -{ +static void KnuthMorrisPrattInit(ssize_t m, ssize_t *T, const char *W) { ssize_t i = 2; ssize_t j = 0; T[0] = -1; @@ -43,10 +39,8 @@ static void KnuthMorrisPrattInit(m, T, W) T[m] = 0; } -static size_t KnuthMorrisPratt(m, T, W, n, S) - const long n, m, T[m + 1]; - const char W[m], S[n]; -{ +static size_t KnuthMorrisPratt(long m, const long *T, const char *W, long n, + const char *S) { long i = 0, j = 0; while (i + j < n) { if (W[i] == S[i + j]) { @@ -60,8 +54,6 @@ static size_t KnuthMorrisPratt(m, T, W, n, S) return j; } -/* clang-format on */ - /** * Searches for fixed-length substring in memory region. * diff --git a/libc/bits/abs.c b/libc/bits/abs.c index b3735735b..655af5c2b 100644 --- a/libc/bits/abs.c +++ b/libc/bits/abs.c @@ -20,6 +20,9 @@ #include "libc/fmt/conv.h" #include "libc/macros.h" +/** + * Returns absolute value of x. + */ int(abs)(int x) { return ABS(x); } diff --git a/libc/bits/bitreverse16.c b/libc/bits/bitreverse16.c index b6b441678..691235104 100644 --- a/libc/bits/bitreverse16.c +++ b/libc/bits/bitreverse16.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Reverses bits in 16-bit word. + */ uint16_t(bitreverse16)(uint16_t x) { return kReverseBits[x & 0x00FF] << 8 | kReverseBits[(x & 0xFF00) >> 8]; } diff --git a/libc/bits/bitreverse32.c b/libc/bits/bitreverse32.c index 9ccc86d1d..acae9021c 100644 --- a/libc/bits/bitreverse32.c +++ b/libc/bits/bitreverse32.c @@ -20,6 +20,9 @@ #include "libc/bits/bits.h" #include "libc/bits/bswap.h" +/** + * Reverses bits in 32-bit word. + */ uint32_t(bitreverse32)(uint32_t x) { x = bswap_32(x); x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1); diff --git a/libc/bits/bitreverse64.c b/libc/bits/bitreverse64.c index 8e9310eb7..06e2156b4 100644 --- a/libc/bits/bitreverse64.c +++ b/libc/bits/bitreverse64.c @@ -20,6 +20,9 @@ #include "libc/bits/bits.h" #include "libc/bits/bswap.h" +/** + * Reverses bits in 64-bit word. + */ uint64_t bitreverse64(uint64_t x) { x = bswap_64(x); x = ((x & 0xaaaaaaaaaaaaaaaa) >> 1) | ((x & 0x5555555555555555) << 1); diff --git a/libc/bits/bitreverse8.c b/libc/bits/bitreverse8.c index fdf3d9ca4..813790cb5 100644 --- a/libc/bits/bitreverse8.c +++ b/libc/bits/bitreverse8.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Reverses bits in 8-bit word. + */ uint8_t(bitreverse8)(uint8_t x) { return kReverseBits[x]; } diff --git a/libc/bits/emptytonull.c b/libc/bits/emptytonull.c index 059f16e6f..0c70c0ba5 100644 --- a/libc/bits/emptytonull.c +++ b/libc/bits/emptytonull.c @@ -17,5 +17,12 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" -const char *emptytonull(const char *s) { return s && !*s ? 0 : s; } +/** + * Returns string where empty string is made null. + * @see nulltoempty() + */ +const char *(emptytonull)(const char *s) { + return s && !*s ? 0 : s; +} diff --git a/libc/bits/firstnonnull.c b/libc/bits/firstnonnull.c index 3bcd6727e..5160bb893 100644 --- a/libc/bits/firstnonnull.c +++ b/libc/bits/firstnonnull.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/runtime.h" +/** + * Returns a or b or aborts if both are null. + */ const char *(firstnonnull)(const char *a, const char *b) { if (a) return a; if (b) return b; diff --git a/libc/bits/gray.c b/libc/bits/gray.c index f941c23b8..d2530c73d 100644 --- a/libc/bits/gray.c +++ b/libc/bits/gray.c @@ -19,6 +19,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Returns gray code for x. + * @see https://en.wikipedia.org/wiki/Gray_code + * @see ungray() + */ uint32_t gray(uint32_t x) { return x ^ (x >> 1); } diff --git a/libc/bits/hamming.c b/libc/bits/hamming.c index 0e9807d6a..71595b388 100644 --- a/libc/bits/hamming.c +++ b/libc/bits/hamming.c @@ -21,6 +21,7 @@ /** * Counts number of different bits. + * @see https://en.wikipedia.org/wiki/Hamming_code */ unsigned long hamming(unsigned long x, unsigned long y) { return popcnt(x ^ y); diff --git a/libc/bits/hilbert.c b/libc/bits/hilbert.c index b2ed8d7cf..2b8b2afab 100644 --- a/libc/bits/hilbert.c +++ b/libc/bits/hilbert.c @@ -36,7 +36,8 @@ static axdx_t RotateQuadrant(long n, long y, long x, long ry, long rx) { /** * Generates Hilbert space-filling curve. * - * @see morton() + * @see https://en.wikipedia.org/wiki/Hilbert_curve + * @see unhilbert() */ long hilbert(long n, long y, long x) { axdx_t m; @@ -56,7 +57,8 @@ long hilbert(long n, long y, long x) { /** * Decodes Hilbert space-filling curve. * - * @see unmorton() + * @see https://en.wikipedia.org/wiki/Hilbert_curve + * @see hilbert() */ axdx_t unhilbert(long n, long i) { axdx_t m; diff --git a/libc/bits/isempty.c b/libc/bits/isempty.c index 22734db07..ed7dc6be6 100644 --- a/libc/bits/isempty.c +++ b/libc/bits/isempty.c @@ -18,4 +18,9 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -bool isempty(const char *s) { return !s || !*s; } +/** + * Returns true if s is empty string or null. + */ +bool isempty(const char *s) { + return !s || !*s; +} diff --git a/libc/bits/morton.c b/libc/bits/morton.c index 680bf4379..78ac08b44 100644 --- a/libc/bits/morton.c +++ b/libc/bits/morton.c @@ -21,6 +21,8 @@ /** * Interleaves bits. + * @see https://en.wikipedia.org/wiki/Z-order_curve + * @see unmorton() */ unsigned long(morton)(unsigned long y, unsigned long x) { x = (x | x << 020) & 0x0000FFFF0000FFFF; diff --git a/libc/bits/nulltoempty.c b/libc/bits/nulltoempty.c index 524ba5e94..df5087dbd 100644 --- a/libc/bits/nulltoempty.c +++ b/libc/bits/nulltoempty.c @@ -17,5 +17,12 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" -const char *nulltoempty(const char *s) { return s ? s : ""; } +/** + * Returns 𝑠 converting null to empty string. + * @see emptytonull() + */ +const char *(nulltoempty)(const char *s) { + return s ? s : ""; +} diff --git a/libc/bits/popcnt.c b/libc/bits/popcnt.c index 02619b973..2c522bd2b 100644 --- a/libc/bits/popcnt.c +++ b/libc/bits/popcnt.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/popcnt.h" +/** + * Returns number of bits set in integer. + */ uint64_t(popcnt)(uint64_t x) { x = x - ((x >> 1) & 0x5555555555555555); x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333); diff --git a/libc/bits/pushpop.h b/libc/bits/pushpop.h index 57c223fa9..44dfd4caa 100644 --- a/libc/bits/pushpop.h +++ b/libc/bits/pushpop.h @@ -3,13 +3,13 @@ #include "libc/macros.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) +#if !defined(__GNUC__) || defined(__STRICT_ANSI__) +#define pushpop(x) (x) +#else /** * PushPop * An elegant weapon for a more civilized age. */ -#if !defined(__GNUC__) || defined(__STRICT_ANSI__) -#define pushpop(x) (x) -#else #define pushpop(x) \ ({ \ typeof(x) Popped; \ diff --git a/libc/bits/rounddown.c b/libc/bits/rounddown.c index 44b015862..d9b23c3f3 100644 --- a/libc/bits/rounddown.c +++ b/libc/bits/rounddown.c @@ -19,4 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -long(rounddown)(long w, long k) { return ROUNDDOWN(w, k); } +/** + * Rounds down 𝑤 to next two power 𝑘. + */ +long(rounddown)(long w, long k) { + return ROUNDDOWN(w, k); +} diff --git a/libc/bits/roundup.c b/libc/bits/roundup.c index dc8228452..b27d18a79 100644 --- a/libc/bits/roundup.c +++ b/libc/bits/roundup.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" +/** + * Rounds up 𝑤 to next two power 𝑘. + */ long(roundup)(long w, long k) { return ROUNDUP(w, k); } diff --git a/libc/bits/roundup2log.c b/libc/bits/roundup2log.c index 843e35016..d93e7c697 100644 --- a/libc/bits/roundup2log.c +++ b/libc/bits/roundup2log.c @@ -22,7 +22,7 @@ /** * Returns 𝑥 rounded up to next two power and log'd. - * @see roundup2pow + * @see roundup2pow() */ unsigned long roundup2log(unsigned long x) { return x > 1 ? (bsrl(x - 1) + 1) : x ? 1 : 0; diff --git a/libc/bits/roundup2pow.c b/libc/bits/roundup2pow.c index d4ae7bafe..483e173e0 100644 --- a/libc/bits/roundup2pow.c +++ b/libc/bits/roundup2pow.c @@ -24,7 +24,7 @@ * Returns 𝑥 rounded up to next two power. * * @define (𝑥>0→2^⌈log₂x⌉, x=0→0, 𝑇→⊥) - * @see rounddown2pow)() + * @see rounddown2pow() */ unsigned long roundup2pow(unsigned long x) { return x > 1 ? 1ul << (bsrl(x - 1) + 1) : x ? 1 : 0; diff --git a/libc/bits/ungray.c b/libc/bits/ungray.c index d37dc86f3..ee7ec8e8d 100644 --- a/libc/bits/ungray.c +++ b/libc/bits/ungray.c @@ -19,6 +19,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Decodes gray code. + * @see https://en.wikipedia.org/wiki/Gray_code + * @see gray() + */ uint32_t ungray(uint32_t x) { x ^= x >> 16; x ^= x >> 8; diff --git a/libc/bits/unmorton.c b/libc/bits/unmorton.c index e54d2d987..103f01d75 100644 --- a/libc/bits/unmorton.c +++ b/libc/bits/unmorton.c @@ -35,6 +35,7 @@ static unsigned long GetOddBits(unsigned long x) { * @param 𝑖 is interleaved index * @return deinterleaved coordinate {ax := 𝑦, dx := 𝑥} * @see en.wikipedia.org/wiki/Z-order_curve + * @see morton() */ axdx_t(unmorton)(unsigned long i) { return (axdx_t){GetOddBits(i >> 1), GetOddBits(i)}; diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 83988fe78..58f23ff8b 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -25,15 +25,15 @@ /** * Changes file permissions via open()'d file descriptor, e.g.: * - * CHECK_NE(-1, chmod("foo/bar.txt", 0644)); - * CHECK_NE(-1, chmod("o/default/program.com", 0755)); - * CHECK_NE(-1, chmod("privatefolder/", 0700)); + * CHECK_NE(-1, chmod("foo/bar.txt", 0644)); + * CHECK_NE(-1, chmod("o/default/program.com", 0755)); + * CHECK_NE(-1, chmod("privatefolder/", 0700)); * * The esoteric bits generally available on System V are: * - * CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit - * CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit - * CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit + * CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit + * CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit + * CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit * * This works on Windows NT if you ignore the error ;-) * diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index f5fec2a80..9e42702a5 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -24,7 +24,7 @@ /** * Does things with file descriptor, via re-imagined hourglass api, e.g. * - * CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC)); + * CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC)); * * @param cmd can be F_{GET,SET}{FD,FL}, etc. * @param arg can be FD_CLOEXEC, etc. depending diff --git a/libc/calls/hefty/dirstream.c b/libc/calls/hefty/dirstream.c index 1b085706b..8218ff5b0 100644 --- a/libc/calls/hefty/dirstream.c +++ b/libc/calls/hefty/dirstream.c @@ -118,13 +118,13 @@ static textwindows noinline struct dirent *readdir$nt(DIR *dir) { /** * Opens directory, e.g. * - * DIR *d; - * struct dirent *e; - * CHECK((d = opendir(path))); - * while ((e = readdir(d))) { - * printf("%s/%s\n", path, e->d_name); - * } - * LOGIFNEG1(closedir(d)); + * DIR *d; + * struct dirent *e; + * CHECK((d = opendir(path))); + * while ((e = readdir(d))) { + * printf("%s/%s\n", path, e->d_name); + * } + * LOGIFNEG1(closedir(d)); * * @returns newly allocated DIR object, or NULL w/ errno * @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM diff --git a/libc/calls/hefty/spawnve.c b/libc/calls/hefty/spawnve.c index 31dff906f..eabe6d284 100644 --- a/libc/calls/hefty/spawnve.c +++ b/libc/calls/hefty/spawnve.c @@ -27,18 +27,18 @@ /** * Launches program, e.g. * - * char buf[2]; - * int ws, pid, fds[3] = {-1, -1, STDERR_FILENO}; - * CHECK_NE(-1, (pid = spawnve(0, fds, commandv("ssh"), - * (char *const[]){"ssh", hostname, "cat", NULL}, - * environ))); - * CHECK_EQ(+2, write(fds[0], "hi", 2)); - * CHECK_NE(-1, close(fds[0])); - * CHECK_EQ(+2, read(fds[1], buf, 2))); - * CHECK_NE(-1, close(fds[1])); - * CHECK_EQ(+0, memcmp(buf, "hi", 2))); - * CHECK_NE(-1, waitpid(pid, &ws, 0)); - * CHECK_EQ(+0, WEXITSTATUS(ws)); + * char buf[2]; + * int ws, pid, fds[3] = {-1, -1, STDERR_FILENO}; + * CHECK_NE(-1, (pid = spawnve(0, fds, commandv("ssh"), + * (char *const[]){"ssh", hostname, "cat", 0}, + * environ))); + * CHECK_EQ(+2, write(fds[0], "hi", 2)); + * CHECK_NE(-1, close(fds[0])); + * CHECK_EQ(+2, read(fds[1], buf, 2))); + * CHECK_NE(-1, close(fds[1])); + * CHECK_EQ(+0, memcmp(buf, "hi", 2))); + * CHECK_NE(-1, waitpid(pid, &ws, 0)); + * CHECK_EQ(+0, WEXITSTATUS(ws)); * * @param stdiofds may optionally be passed to customize standard i/o * @param stdiofds[𝑖] may be -1 to receive a pipe() fd @@ -49,6 +49,7 @@ * @param envp[0,n-2] specifies "foo=bar" environment variables * @param envp[n-1] is NULL * @return pid of child, or -1 w/ errno + * @deprecated just use vfork() and execve() */ int spawnve(unsigned flags, int stdiofds[3], const char *program, char *const argv[], char *const envp[]) { diff --git a/libc/calls/isatty.c b/libc/calls/isatty.c index 1002046c4..07f94d56c 100644 --- a/libc/calls/isatty.c +++ b/libc/calls/isatty.c @@ -27,7 +27,7 @@ * @asyncsignalsafe */ bool32 isatty(int fd) { - char buf[sizeof(uint16_t) * 4] forcealign(2); + _Alignas(short) char buf[sizeof(uint16_t) * 4]; if (!IsWindows()) { return ioctl$sysv(fd, TIOCGWINSZ, &buf) != -1; } else { diff --git a/libc/calls/kntprioritycombos.c b/libc/calls/kntprioritycombos.c index ce88bcd9f..13853576a 100644 --- a/libc/calls/kntprioritycombos.c +++ b/libc/calls/kntprioritycombos.c @@ -21,38 +21,37 @@ #include "libc/calls/kntprioritycombos.internal.h" #include "libc/limits.h" #include "libc/macros.h" +#include "libc/nexgen32e/ffs.h" #include "libc/nt/enum/processcreationflags.h" #include "libc/nt/enum/threadpriority.h" -#define FFS(x) __builtin_ffs(x) - const struct NtPriorityCombo kNtPriorityCombos[] = { - {-20, FFS(kNtHighPriorityClass), kNtThreadPriorityHighest, 15}, - {-18, FFS(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-17, FFS(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-15, FFS(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-13, FFS(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14}, - {-11, FFS(kNtHighPriorityClass), kNtThreadPriorityNormal, 13}, - {-9, FFS(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12}, - {-7, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11}, - {-5, FFS(kNtHighPriorityClass), kNtThreadPriorityLowest, 11}, - {-3, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10}, - {-1, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9}, - {0, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9}, - {1, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8}, - {2, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8}, - {3, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7}, - {4, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7}, - {5, FFS(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6}, - {6, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6}, - {7, FFS(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5}, - {9, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5}, - {11, FFS(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4}, - {13, FFS(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3}, - {15, FFS(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2}, - {17, FFS(kNtHighPriorityClass), kNtThreadPriorityIdle, 1}, - {18, FFS(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1}, - {19, FFS(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1}, + {-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15}, + {-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14}, + {-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13}, + {-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12}, + {-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11}, + {-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11}, + {-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10}, + {-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9}, + {0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9}, + {1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8}, + {2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8}, + {3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7}, + {4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7}, + {5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6}, + {6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6}, + {7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5}, + {9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5}, + {11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4}, + {13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3}, + {15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2}, + {17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1}, + {18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1}, + {19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1}, }; const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos); diff --git a/libc/calls/readansi.c b/libc/calls/readansi.c index 2f16a63df..92a60975b 100644 --- a/libc/calls/readansi.c +++ b/libc/calls/readansi.c @@ -29,11 +29,11 @@ * how long each sequence is, so that each read consumes a single thing * from the underlying file descriptor, e.g. * - * "a" ALFA - * "\316\261" ALPHA - * "\033[A" CURSOR UP - * "\033[38;5;202m" ORANGERED - * "\eOP" PF1 + * "a" ALFA + * "\316\261" ALPHA + * "\033[A" CURSOR UP + * "\033[38;5;202m" ORANGERED + * "\eOP" PF1 * * This routine generalizes to ascii, utf-8, chorded modifier keys, * function keys, color codes, c0/c1 control codes, cursor movement, @@ -48,9 +48,9 @@ * tokenized as a single read. Lastly note, this function has limited * support for UNICODE representations of C0/C1 control codes, e.g. * - * "\000" NUL - * "\300\200" NUL - * "\302\233A" CURSOR UP + * "\000" NUL + * "\300\200" NUL + * "\302\233A" CURSOR UP * * @param buf is guaranteed to receive a NUL terminator if size>0 * @return number of bytes read (helps differentiate "\0" vs. "") diff --git a/libc/calls/setitimer.c b/libc/calls/setitimer.c index 4cf005417..97544bd0c 100644 --- a/libc/calls/setitimer.c +++ b/libc/calls/setitimer.c @@ -28,27 +28,28 @@ * * Raise SIGALRM every 1.5s: * - * CHECK_NE(-1, sigaction(SIGALRM, - * &(struct sigaction){.sa_sigaction = missingno}, - * NULL)); - * CHECK_NE(-1, setitimer(ITIMER_REAL, - * &(const struct itimerval){{1, 500000}, {1, 500000}}, - * NULL)); + * CHECK_NE(-1, sigaction(SIGALRM, + * &(struct sigaction){.sa_sigaction = missingno}, + * NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, + * &(const struct itimerval){{1, 500000}, + * {1, 500000}}, + * NULL)); * * Set single-shot 50ms timer callback to interrupt laggy connect(): * - * CHECK_NE(-1, sigaction(SIGALRM, - * &(struct sigaction){.sa_sigaction = missingno, - * .sa_flags = SA_RESETHAND}, - * NULL)); - * CHECK_NE(-1, setitimer(ITIMER_REAL, - * &(const struct itimerval){{0, 0}, {0, 50000}}, - * NULL)); - * if (connect(...) == -1 && errno == EINTR) { ... } + * CHECK_NE(-1, sigaction(SIGALRM, + * &(struct sigaction){.sa_sigaction = missingno, + * .sa_flags = SA_RESETHAND}, + * NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, + * &(const struct itimerval){{0, 0}, {0, 50000}}, + * NULL)); + * if (connect(...) == -1 && errno == EINTR) { ... } * * Disarm timer: * - * CHECK_NE(-1, setitimer(ITIMER_REAL, &(const struct itimerval){0}, NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, &(const struct itimerval){0}, NULL)); * * Be sure to check for EINTR on your i/o calls, for best low latency. * diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 18f92556a..b4383ba27 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -112,10 +112,10 @@ static void sigaction$native2cosmo(union metasigaction *sa) { /** * Installs handler for kernel interrupt, e.g.: * - * void GotCtrlC(int sig, siginfo_t *si, ucontext_t *ctx); - * struct sigaction sa = {.sa_sigaction = GotCtrlC, - * .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO}; - * CHECK_NE(-1, sigaction(SIGINT, &sa, NULL)); + * void GotCtrlC(int sig, siginfo_t *si, ucontext_t *ctx); + * struct sigaction sa = {.sa_sigaction = GotCtrlC, + * .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO}; + * CHECK_NE(-1, sigaction(SIGINT, &sa, NULL)); * * @see xsigaction() for a much better api * @asyncsignalsafe diff --git a/libc/calls/sigprocmask.c b/libc/calls/sigprocmask.c index ac32bfe1a..fc8d3e4d0 100644 --- a/libc/calls/sigprocmask.c +++ b/libc/calls/sigprocmask.c @@ -26,9 +26,9 @@ /** * Changes program signal blocking state, e.g.: * - * sigset_t oldmask; - * sigprocmask(SIG_BLOCK, &kSigsetFull, &oldmask); - * sigprocmask(SIG_SETMASK, &oldmask, NULL); + * sigset_t oldmask; + * sigprocmask(SIG_BLOCK, &kSigsetFull, &oldmask); + * sigprocmask(SIG_SETMASK, &oldmask, NULL); * * @param how can be SIG_BLOCK (U), SIG_UNBLOCK (/), SIG_SETMASK (=) * @param set is the new mask content (optional) diff --git a/libc/dce.h b/libc/dce.h index 0179c04ec..249920545 100644 --- a/libc/dce.h +++ b/libc/dce.h @@ -5,6 +5,7 @@ │ cosmopolitan § autotune » dead code elimination │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#ifndef SUPPORT_VECTOR /** * Supported Platforms Tuning Knob (Runtime & Compile-Time) * @@ -17,7 +18,6 @@ * offer marginal improvements in terms of code size and performance, at * the cost of portability. */ -#ifndef SUPPORT_VECTOR #define SUPPORT_VECTOR 0b11111111 #endif #define LINUX 1 diff --git a/libc/elf/struct/rela.h b/libc/elf/struct/rela.h index 51f0f68f5..5fcbc8ea9 100644 --- a/libc/elf/struct/rela.h +++ b/libc/elf/struct/rela.h @@ -10,7 +10,7 @@ typedef struct Elf64_Rela { * ELF64_R_TYPE(r_info) → R_X86_64_{64,PC32,GOTPCRELX,...} * ELF64_R_INFO(sym, type) → r_info */ - /*u64*/ Elf64_Xword r_info; /** @see ELF64_R_{SYM,SIZE,INFO} */ + /*u64*/ Elf64_Xword r_info; /* ELF64_R_{SYM,SIZE,INFO} */ /*i64*/ Elf64_Sxword r_addend; } Elf64_Rela; diff --git a/libc/fmt/bing.c b/libc/fmt/bing.c index aab1a1206..db9ef0ec8 100644 --- a/libc/fmt/bing.c +++ b/libc/fmt/bing.c @@ -26,23 +26,23 @@ * * Cosmopolitan displays RADIX-256 numbers using these digits: * - * 0123456789abcdef - * 0 ☺☻♥♦♣♠•◘○◙♂♀♪♫☼ - * 1►◄↕‼¶§▬↨↑↓→←∟↔▲▼ - * 2 !"#$%&'()*+,-./ - * 30123456789:;<=>? - * 4@ABCDEFGHIJKLMNO - * 5PQRSTUVWXYZ[\]^_ - * 6`abcdefghijklmno - * 7pqrstuvwxyz{|}~⌂ - * 8ÇüéâäàåçêëèïîìÄÅ - * 9ÉæÆôöòûùÿÖÜ¢£¥€ƒ - * aáíóúñѪº¿⌐¬½¼¡«» - * b░▒▓│┤╡╢╖╕╣║╗╝╜╛┐ - * c└┴┬├─┼╞╟╚╔╩╦╠═╬╧ - * d╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ - * eαßΓπΣσμτΦΘΩδ∞φε∩ - * f≡±≥≤⌠⌡÷≈°∙·√ⁿ²■λ + * 0123456789abcdef + * 0 ☺☻♥♦♣♠•◘○◙♂♀♪♫☼ + * 1►◄↕‼¶§▬↨↑↓→←∟↔▲▼ + * 2 !"#$%&'()*+,-./ + * 30123456789:;<=>? + * 4@ABCDEFGHIJKLMNO + * 5PQRSTUVWXYZ[\]^_ + * 6`abcdefghijklmno + * 7pqrstuvwxyz{|}~⌂ + * 8ÇüéâäàåçêëèïîìÄÅ + * 9ÉæÆôöòûùÿÖÜ¢£¥€ƒ + * aáíóúñѪº¿⌐¬½¼¡«» + * b░▒▓│┤╡╢╖╕╣║╗╝╜╛┐ + * c└┴┬├─┼╞╟╚╔╩╦╠═╬╧ + * d╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ + * eαßΓπΣσμτΦΘΩδ∞φε∩ + * f≡±≥≤⌠⌡÷≈°∙·√ⁿ²■λ * * IBM designed these glyphs for the PC to map onto the display bytes at * (char *)0xb8000. Because IBM authorized buyers of its PCs to inspect diff --git a/libc/integral/c.inc b/libc/integral/c.inc index f1f51b9b3..05357b081 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -18,10 +18,6 @@ #define __far #endif -/** - * Gets type of expression. - * @see autotype() which is a better alternative for certain use cases - */ #if !defined(__GNUC__) && __cplusplus + 0 >= 201103L #define typeof(x) decltype(x) #elif (defined(__STRICT_ANSI__) || !defined(__GNUC__)) && \ @@ -143,35 +139,10 @@ typedef __UINT32_TYPE__ uint32_t; typedef __INT64_TYPE__ int64_t; typedef __UINT64_TYPE__ uint64_t; -/** - * AX:DX register pair. - * - * Every ABI we support permits functions to return two machine words. - * Normally it's best to define a one-off struct. Sometimes we don't - * want the boilerplate. - * - * @see System V Application Binary Interface NexGen32e Architecture - * Processor Supplement, Version 1.0, December 5th, 2018 - * @see agner.org/optimize/calling_conventions.pdf (chapter 6) - * @see LISP primitives CONS[CAR,CDR] w/ IBM 704 naming - * @see int128_t - */ typedef struct { intptr_t ax, dx; } axdx_t; -/* - * GCC, Clang, and System V ABI all incorrectly define intmax_t. - * - * “[intmax_t] designates a signed integer type capable of - * representing any value of any signed integer type.” - * ──Quoth ISO/IEC 9899:201x 7.20.1.5 - * - * This surprising contradiction is most likely due to Linux distro - * practices of using dynamic shared objects which needs to change. - * - * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2303.pdf - */ #ifdef __SIZEOF_INTMAX__ #undef __SIZEOF_INTMAX__ #endif @@ -210,11 +181,6 @@ typedef uint64_t uintmax_t; #define mallocesque reallocesque returnspointerwithnoaliases #define interruptfn nocallersavedregisters forcealignargpointer -/** - * Declares combinator, i.e. never reads/writes global memory. - * Thus enabling LICM, CSE, DCE, etc. optimizations. - * @see nosideeffect - */ #ifndef pureconst #ifndef __STRICT_ANSI__ #define pureconst __attribute__((__const__)) @@ -223,9 +189,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Aligns automatic or static variable. - */ #ifndef forcealign #ifndef __STRICT_ANSI__ #define forcealign(bytes) __attribute__((__aligned__(bytes))) @@ -234,21 +197,12 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Disables alignment. - * @param opt_bytes defaults to __BIGGEST_ALIGNMENT__ - * @see nosideeffect - */ #ifndef __STRICT_ANSI__ #define thatispacked __attribute__((__packed__)) #else #define thatispacked #endif -/** - * Declares prototype as using well-known format string DSL. - * Thereby allowing compiler to identify certain bugs. - */ #ifndef __STRICT_ANSI__ #define printfesque(n) __attribute__((__format__(__gnu_printf__, n, n + 1))) #define scanfesque(n) __attribute__((__format__(__gnu_scanf__, n, n + 1))) @@ -297,11 +251,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype as never mutating global memory. - * Thus enabling CSE, DCE, LICM [clang-only?], etc. optimizations. - * @see pureconst - */ #ifndef nosideeffect #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__pure__) || \ @@ -332,18 +281,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Makes function behave as much like macro as possible, meaning: - * - * 1. always inlined, i.e. even with -fno-inline - * 2. unlinkable, i.e. elf data is not generated - * 3. steppable, i.e. dwarf data is generated - * 4. unprofilable - * 5. unhookable - * - * @note consider static or writing a macro - * @see externinline - */ #ifndef forceinline #ifdef __cplusplus #define forceinline inline @@ -372,19 +309,6 @@ typedef uint64_t uintmax_t; #endif /* __cplusplus */ #endif /* forceinline */ -/** - * Permits untyped or punned memory manipulation w/o asm. - * - * “The fundamental problem is that it is not possible to write real - * programs using the X3J11 definition of C. The committee has created - * an unreal language that no one can or will actually use. While the - * problems of `const' may owe to careless drafting of the - * specification, `noalias' is an altogether mistaken notion, and must - * not survive.” ──Dennis Ritchie in 1988-03-20. - * - * @see asm(), memcpy(), memset(), read32be(), etc. - * @see unsigned char - */ #ifndef mayalias #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__may_alias__) || \ @@ -395,11 +319,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype as returning freeable resource. - * Compilation will fail if caller ignores return value. - * @see gc(), free(), close(), etc. - */ #ifndef nodiscard #if !defined(__STRICT_ANSI__) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \ @@ -410,10 +329,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares variadic function as needing NULL sentinel argument. - * @see execl() for example - */ #ifndef nullterminated #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__sentinel__) || __GNUC__ >= 4) @@ -448,10 +363,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Relocates function to .text.unlikely section of binary. - * @note can be used to minimize page-faults and improve locality - */ #ifndef relegated #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__cold__) || \ @@ -470,11 +381,6 @@ typedef uint64_t uintmax_t; #define warnifused(s) #endif -/** - * Relocates function to .text.hot section of binary. - * @note can be used to minimize page-faults w/ improved locality - * @note most appropriately automated by profile-guided opts - */ #ifndef firstclass #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__hot__) || \ @@ -485,12 +391,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares all or specific parameters as never receiving NULL. - * - * This can be checked at both compile-time (only for constexprs) and - * runtime too (only in MODE=dbg mode) by synthetic Ubsan code. - */ #ifndef paramsnonnull #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__nonnull__) || \ @@ -501,22 +401,12 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares array argument w/ minimum size contract, e.g. - * - * int foo(int bar[hasatleast 2]) { ... } - */ #if __STDC_VERSION__ + 0 >= 199901L #define hasatleast static #else #define hasatleast #endif -/** - * Qualifies char pointer so it's treated like every other type. - * - * int foo(int bar[hasatleast 2]) { ... } - */ #if __STDC_VERSION__ + 0 < 199901L && !defined(restrict) #if !defined(__STRICT_ANSI__) && !defined(__cplusplus) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301 || defined(_MSC_VER)) @@ -527,10 +417,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype that can't mutate caller's static variables. - * @note consider more .c files or declare in function - */ #ifndef nocallback #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__leaf__) || \ @@ -554,11 +440,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to not optimize function definition. - * - * @todo this is dangerous delete? - */ #ifndef nooptimize #ifndef __STRICT_ANSI__ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -572,13 +453,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to generate as little code as possible for function. - * - * This does the same thing as relegated, but without relocation. - * - * @todo this is dangerous delete? - */ #ifndef optimizesize #ifndef __STRICT_ANSI__ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -592,15 +466,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to always heavily optimize function. - * - * This keyword provides an alternative to build flag tuning, in cases - * where the compiler is reluctant to vectorize mathematical code that's - * written in standards-compliant C rather than GCC extensions. - * - * @todo this is dangerous delete? - */ #ifndef optimizespeed #if !defined(__STRICT_ANSI__) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -611,9 +476,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype that behaves similar to setjmp() or vfork(). - */ #ifndef returnstwice #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__returns_twice__) || \ @@ -624,10 +486,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to not emit DWARF assembly for function. - * @see artificial - */ #ifndef nodebuginfo #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__nodebug__) || defined(__llvm__)) @@ -637,10 +495,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Associates debug information with call site. - * @see nodebuginfo - */ #ifndef artificial #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__artificial__) || \ @@ -651,11 +505,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines function as specially compiled for newer cpu model. - * @see -ftree-vectorize and consider assembly - * @see libc/dce.h - */ #ifndef microarchitecture #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__target__) || \ @@ -666,10 +515,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Compiles function multiple times for different cpu models. - * @see libc/dce.h - */ #ifndef targetclones #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__target_clones__) || __GNUC__ >= 6) @@ -679,10 +524,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines function with prologue that fixes misaligned stack. - * @see nocallersavedregisters and consider assembly - */ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__force_align_arg_pointer__) #define forcealignargpointer __attribute__((__force_align_arg_pointer__)) @@ -690,12 +531,6 @@ typedef uint64_t uintmax_t; #define forcealignargpointer "need modern compiler" #endif -/** - * Declares prototype as never returning NULL. - * - * This is checked at compile-time for constexprs. It'll be checked at - * runtime too by synthetic code, only in MODE=dbg mode. - */ #ifndef returnsnonnull #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__returns_nonnull__) || \ @@ -706,13 +541,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Attests return value is aligned. - * - * @param (alignment) - * @param (alignment, misalignment) - * @see attributeallocalign(), returnspointerwithnoaliases, mallocesque - */ #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__assume_aligned__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) @@ -721,10 +549,6 @@ typedef uint64_t uintmax_t; #define returnsaligned(x) #endif -/** - * Declares prototype as behaving similar to malloc(). - * @see attributeallocsize(), attributeallocalign() - */ #ifndef returnspointerwithnoaliases #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__malloc__) || \ @@ -757,20 +581,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines variable as having same type as right-hand side. - * - * This enables safe, backwards-compatible, non-explosive macros, e.g.: - * - * #define bar(FOO) \ - * ({ \ - * autotype(FOO) Foo = (FOO); \ - * Foo + Foo * 2; \ - * }) - * - * @param x must be identical to rhs - * @note typeof goes back to gcc 2.x - */ #if __cplusplus + 0 >= 201103L #define autotype(x) auto #elif ((__has_builtin(auto_type) || defined(__llvm__) || \ @@ -781,27 +591,16 @@ typedef uint64_t uintmax_t; #define autotype(x) typeof(x) #endif -/** - * Defines interrupt handler that can call non-interrupt functions. - * @see forcealignargpointer, -mgeneral-regs-only and consider assembly - */ #if __GNUC__ >= 7 || __has_attribute(__no_caller_saved_registers__) #define nocallersavedregisters __attribute__((__no_caller_saved_registers__)) #else #define nocallersavedregisters "need modern compiler" #endif -/** - * Attests that execution of statement is impossible. - */ #ifndef unreachable #define unreachable __builtin_unreachable() #endif -/** - * Statement that does nothing. - * @note can help avoid drama w/ linters, warnings, formatters, etc. - */ #define donothing \ do { \ } while (0) @@ -857,9 +656,6 @@ typedef uint64_t uintmax_t; #define initarray _Section(".init_array") #endif -/** - * Systemic suppressions. - */ #ifndef __STRICT_ANSI__ #if defined(__GNUC__) || defined(__llvm__) #pragma GCC diagnostic ignored "-Wsign-compare" /* lint needs to change */ @@ -908,17 +704,6 @@ typedef uint64_t uintmax_t; #endif /* !GCC && LLVM */ #endif /* ANSI */ -/** - * Elevate warnings of material consequence. - * - * These aren't stylistic in nature; but are perfectly fine to disable, - * assuming we're ok with the compiler simply generating a runtime crash - * instead. Otherwise what usually happens with these is that a weakness - * is introduced, important optimizations can't be performed; or worst - * of all: the code will need patching if ported to a toy or any machine - * designed by an engineer who hadn't understood John von Neumann at the - * time, e.g. 1's complement, big endian, under 32bit word size, etc. - */ #ifndef __W__ #ifndef __STRICT_ANSI__ #if defined(__GNUC__) || defined(__llvm__) @@ -965,10 +750,6 @@ typedef uint64_t uintmax_t; #endif /* ANSI */ #endif /* -w */ -/** - * Sets manual breakpoint. - * @see showcrashreports() for auto gdb attach - */ #define DebugBreak() asm("int3") #define VEIL(CONSTRAINT, EXPRESSION) \ @@ -991,10 +772,6 @@ typedef uint64_t uintmax_t; 0; \ }) -/** - * Pulls another module, by symbol, into linkage. - * @note nop is discarded by ape/ape.lds - */ #define YOINK(SYMBOL) \ do { \ _Static_assert(!__builtin_types_compatible_p(typeof(SYMBOL), char[]), \ @@ -1006,29 +783,15 @@ typedef uint64_t uintmax_t; : "X"(SYMBOL)); \ } while (0) -/** - * Pulls another module into linkage from top-level scope. - * @note nop is discarded by ape/ape.lds - */ #define STATIC_YOINK(SYMBOLSTR) \ asm(".pushsection .yoink\n\tnop\t\"" SYMBOLSTR "\"\n\t.popsection") -/** - * Pulls source file into ZIP portion of binary. - * @see build/rules.mk which defines the wildcard build rule %.zip.o - */ #if !defined(IM_FEELING_NAUGHTY) && !defined(__STRICT_ANSI__) #define STATIC_YOINK_SOURCE(PATH) STATIC_YOINK(PATH) #else #define STATIC_YOINK_SOURCE(PATH) #endif -/** - * Pulls source of object being compiled into zip. - * @note automates most compliance with gpl terms - * @see libc/zipos/zipcentraldir.S - * @see ape/ape.lds - */ #ifdef __BASE_FILE__ STATIC_YOINK_SOURCE(__BASE_FILE__); #endif diff --git a/libc/integral/lp64.inc b/libc/integral/lp64.inc index b60bbda86..387f2eb67 100644 --- a/libc/integral/lp64.inc +++ b/libc/integral/lp64.inc @@ -67,4 +67,4 @@ #define __INT_FAST64_TYPE__ __INT64_TYPE__ #define __UINT_FAST64_TYPE__ __UINT64_TYPE__ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 7df7ba0e5..ae09ea416 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -1,12 +1,3 @@ -/** - * @fileoverview Cosmopolitan Preprocessor / Language Normalization. - * - * This is our lowest-level header file. You don't need to include it, - * since we require that compilers be configured to do so automatically, - * and the -include flag is the safest bet. Further note polyfills here - * shouldn't be taken as indicators of intent to support. - */ - #define __COSMOPOLITAN__ 1 #ifndef __COUNTER__ diff --git a/libc/math.h b/libc/math.h index bfaa82597..f17ad172a 100644 --- a/libc/math.h +++ b/libc/math.h @@ -289,11 +289,6 @@ void sincosl(long double, long double *, long double *); │ cosmopolitan § mathematics » x87 ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#if 0 -/** - * Asks FPU to push well-known numbers to its own stack. - */ -#endif #define fldz() __X87_CONST(fldz, 0x0p+0) #define fld1() __X87_CONST(fld1, 0x8p-3) #define fldpi() __X87_CONST(fldpi, M_PI) diff --git a/libc/mem/vasprintf.c b/libc/mem/vasprintf.c index 9f4b2d174..3317e3a44 100644 --- a/libc/mem/vasprintf.c +++ b/libc/mem/vasprintf.c @@ -30,7 +30,7 @@ * @see xasprintf() for a better API */ int(vasprintf)(char **strp, const char *fmt, va_list va) { - /** + /* * This implementation guarantees the smallest possible allocation, * using an optimistic approach w/o changing asymptotic complexity. */ diff --git a/libc/nexgen32e/ffs.S b/libc/nexgen32e/ffs.S index 39be2372c..1391f16d8 100644 --- a/libc/nexgen32e/ffs.S +++ b/libc/nexgen32e/ffs.S @@ -38,8 +38,8 @@ / @asyncsignalsafe ffs: .leafprologue .profilable - bsf %edi,%eax or $-1,%edx + bsf %edi,%eax cmovz %edx,%eax inc %eax .leafepilogue diff --git a/libc/nexgen32e/ffs.h b/libc/nexgen32e/ffs.h index 6a1617630..07d1219b9 100644 --- a/libc/nexgen32e/ffs.h +++ b/libc/nexgen32e/ffs.h @@ -3,9 +3,29 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +/* + * BIT SCANNING 101 + * ctz(𝑥) 31^clz(𝑥) clz(𝑥) + * uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥) + * 0x00000000 wut 32 0 wut 32 + * 0x00000001 0 0 1 0 31 + * 0x80000001 0 0 1 31 0 + * 0x80000000 31 31 32 31 0 + * 0x00000010 4 4 5 4 27 + * 0x08000010 4 4 5 27 4 + * 0x08000000 27 27 28 27 4 + * 0xffffffff 0 0 1 31 0 + */ + int ffs(int) pureconst; -int ffsl(long int) pureconst; -int ffsll(long long int) pureconst; +int ffsl(long) pureconst; +int ffsll(long long) pureconst; + +#ifdef __GNUC__ +#define ffs(u) __builtin_ffs(u) +#define ffsl(u) __builtin_ffsl(u) +#define ffsll(u) __builtin_ffsll(u) +#endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/nexgen32e/ffsl.S b/libc/nexgen32e/ffsl.S index 44327c062..84a2540eb 100644 --- a/libc/nexgen32e/ffsl.S +++ b/libc/nexgen32e/ffsl.S @@ -38,8 +38,8 @@ / @asyncsignalsafe ffsl: .leafprologue .profilable - bsf %rdi,%rax or $-1,%edx + bsf %rdi,%rax cmovz %edx,%eax inc %eax .leafepilogue diff --git a/libc/nexgen32e/kcpuids.h b/libc/nexgen32e/kcpuids.h index f104f06fc..1c0f9def8 100644 --- a/libc/nexgen32e/kcpuids.h +++ b/libc/nexgen32e/kcpuids.h @@ -29,13 +29,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * Globally precomputed x86 CPUID values. - * - * @note Referencing Is Initialization (RII) - * @note Protected with PIRO - * @see X86_HAVE() - */ extern const unsigned kCpuids[KCPUIDS_LEN][4]; COSMOPOLITAN_C_END_ diff --git a/libc/nt/thunk/msabi.h b/libc/nt/thunk/msabi.h index 89793d506..10cfaedf5 100644 --- a/libc/nt/thunk/msabi.h +++ b/libc/nt/thunk/msabi.h @@ -2,6 +2,9 @@ #define COSMOPOLITAN_LIBC_NT_THUNK_MSABI_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) +#if !defined(__STRICT_ANSI__) && \ + (__GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \ + (__has_attribute(__ms_abi__) || defined(__llvm__))) /** * Defines function as using Microsoft x64 calling convention. * @@ -9,13 +12,10 @@ * generate code that calls MS ABI functions directly, without needing * to jump through the assembly thunks. */ -#if !defined(__STRICT_ANSI__) && \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \ - (__has_attribute(__ms_abi__) || defined(__llvm__))) #define __msabi __attribute__((__ms_abi__)) #endif -/** +/* * Returns true if header should provide MS-ABI overrides. */ #ifndef ShouldUseMsabiAttribute diff --git a/libc/rand/rand32.c b/libc/rand/rand32.c index d8b65c64c..c072f5755 100644 --- a/libc/rand/rand32.c +++ b/libc/rand/rand32.c @@ -35,7 +35,7 @@ nodebuginfo uint32_t(rand32)(void) { } else { devrand(&res, sizeof(res)); } - hidden extern uint32_t g_rando32; + extern uint32_t g_rando32 hidden; res ^= MarsagliaXorshift32(&g_rando32); } return res; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 800d4f096..849cf4c86 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -42,9 +42,9 @@ /** * Beseeches system for page-table entries. * - * char *p = mmap(NULL, 65536, PROT_READ | PROT_WRITE, - * MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - * munmap(p, 65536); + * char *p = mmap(NULL, 65536, PROT_READ | PROT_WRITE, + * MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + * munmap(p, 65536); * * @param addr optionally requests a particular virtual base address, * which needs to be 64kb aligned if passed (for NT compatibility) diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 48cd378be..5b82db322 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -157,29 +157,29 @@ static textwindows wontreturn void WinMainNew(void) { * The Cosmopolitan Runtime provides the following services, which aim * to bring Windows NT behavior closer in harmony with System Five: * - * 1. We configure CMD.EXE for UTF-8 and enable ANSI colors on Win10. + * 1. We configure CMD.EXE for UTF-8 and enable ANSI colors on Win10. * - * 2. Command line arguments are passed as a blob of UTF-16 text. We - * chop them up into an char *argv[] UTF-8 data structure, in - * accordance with the DOS conventions for argument quoting. + * 2. Command line arguments are passed as a blob of UTF-16 text. We + * chop them up into an char *argv[] UTF-8 data structure, in + * accordance with the DOS conventions for argument quoting. * - * 3. Environment variables are passed to us as a sorted UTF-16 double - * NUL terminated list. We translate this to char ** using UTF-8. + * 3. Environment variables are passed to us as a sorted UTF-16 double + * NUL terminated list. We translate this to char ** using UTF-8. * - * 4. Allocates new stack at a high address. NT likes to choose a - * stack address that's beneath the program image. We want to be - * able to assume that stack addresses are located at higher - * addresses than heap and program memory. + * 4. Allocates new stack at a high address. NT likes to choose a + * stack address that's beneath the program image. We want to be + * able to assume that stack addresses are located at higher + * addresses than heap and program memory. * - * 5. Windows users are afraid of "drive-by downloads" where someone - * might accidentally an evil DLL to their Downloads folder which - * then overrides the behavior of a legitimate EXE being run from - * the downloads folder. Since we don't even use dynamic linking, - * we've cargo culted some API calls, that may harden against it. + * 5. Windows users are afraid of "drive-by downloads" where someone + * might accidentally an evil DLL to their Downloads folder which + * then overrides the behavior of a legitimate EXE being run from + * the downloads folder. Since we don't even use dynamic linking, + * we've cargo culted some API calls, that may harden against it. * - * 6. Finally, we need fork. Microsoft designed Windows to prevent us - * from having fork() so we pass pipe handles in an environment - * variable literally copy all the memory. + * 6. Finally, we need fork. Microsoft designed Windows to prevent us + * from having fork() so we pass pipe handles in an environment + * variable literally copy all the memory. * * @param hInstance call GetModuleHandle(NULL) from main if you need it */ diff --git a/libc/stdio/g_stderr.c b/libc/stdio/g_stderr.c index d48712775..2beed9144 100644 --- a/libc/stdio/g_stderr.c +++ b/libc/stdio/g_stderr.c @@ -22,7 +22,11 @@ STATIC_YOINK("_init_g_stderr"); +/** + * Pointer to standard error stream. + */ FILE *stderr; + hidden FILE g_stderr; hidden unsigned char g_stderr_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/stdio/g_stdin.c b/libc/stdio/g_stdin.c index 63249d969..a31deef1d 100644 --- a/libc/stdio/g_stdin.c +++ b/libc/stdio/g_stdin.c @@ -22,7 +22,11 @@ STATIC_YOINK("_init_g_stdin"); +/** + * Pointer to standard input stream. + */ FILE *stdin; + hidden FILE g_stdin; hidden unsigned char g_stdin_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/stdio/g_stdout.c b/libc/stdio/g_stdout.c index 2ef26577c..2b09eaa4f 100644 --- a/libc/stdio/g_stdout.c +++ b/libc/stdio/g_stdout.c @@ -25,7 +25,11 @@ STATIC_YOINK("_init_g_stdout"); +/** + * Pointer to standard output stream. + */ FILE *stdout; + hidden FILE g_stdout; hidden unsigned char g_stdout_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/str/isalnum.c b/libc/str/isalnum.c index 1b94dc173..3ad2d74b4 100644 --- a/libc/str/isalnum.c +++ b/libc/str/isalnum.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is lower, alpha, or digit. + */ int isalnum(int c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); diff --git a/libc/str/isalpha.c b/libc/str/isalpha.c index 64a6d94a2..2af6db7f4 100644 --- a/libc/str/isalpha.c +++ b/libc/str/isalpha.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is upper or lower. + */ int isalpha(int c) { return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); } diff --git a/libc/str/isascii.c b/libc/str/isascii.c index 5313b23d2..053561360 100644 --- a/libc/str/isascii.c +++ b/libc/str/isascii.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is ascii. + */ int isascii(int c) { return 0x00 <= c && c <= 0x7F; } diff --git a/libc/str/isblank.c b/libc/str/isblank.c index f1f43ec8a..3b17bfff6 100644 --- a/libc/str/isblank.c +++ b/libc/str/isblank.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is space or tab. + */ int isblank(int c) { return c == ' ' || c == '\t'; } diff --git a/libc/str/iscntrl.c b/libc/str/iscntrl.c index 423965e92..87bd0aa54 100644 --- a/libc/str/iscntrl.c +++ b/libc/str/iscntrl.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is C0 ASCII control code or DEL. + */ int iscntrl(int c) { return (0x00 <= c && c <= 0x1F) || c == 0x7F; } diff --git a/libc/str/isdigit.c b/libc/str/isdigit.c index 208528c09..83bafcad7 100644 --- a/libc/str/isdigit.c +++ b/libc/str/isdigit.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is decimal digit. + */ int isdigit(int c) { return '0' <= c && c <= '9'; } diff --git a/libc/str/islower.c b/libc/str/islower.c index 2578519b4..c1ac7629a 100644 --- a/libc/str/islower.c +++ b/libc/str/islower.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is lowercase alpha ascii character. + */ int islower(int c) { return 'a' <= c && c <= 'z'; } diff --git a/libc/str/isspace.c b/libc/str/isspace.c index e5873bad4..dcd64f69e 100644 --- a/libc/str/isspace.c +++ b/libc/str/isspace.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns true if c is space, \t, \r, \n, \f, or \v. + */ int isspace(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v'; diff --git a/libc/str/isupper.c b/libc/str/isupper.c index a374f695d..736eb2bef 100644 --- a/libc/str/isupper.c +++ b/libc/str/isupper.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is uppercase alpha ascii character. + */ int isupper(int c) { return 'A' <= c && c <= 'Z'; } diff --git a/libc/str/iswcntrl.c b/libc/str/iswcntrl.c index 4b67fae7e..3f33ce988 100644 --- a/libc/str/iswcntrl.c +++ b/libc/str/iswcntrl.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if wc is C0 or C1 control code. + */ int iswcntrl(wint_t wc) { return (0x00 <= wc && wc <= 0x1F) || (0x7F <= wc && wc <= 0x9F); } diff --git a/libc/str/isxdigit.c b/libc/str/isxdigit.c index 7ef928d70..2b3c8fbb8 100644 --- a/libc/str/isxdigit.c +++ b/libc/str/isxdigit.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns true if c is hexadecimal digit. + */ int isxdigit(int c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index 5569c4f64..e2b008c15 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -28,17 +28,17 @@ * * For example, strictly: * - * char buf[16]; - * CHECK_NOTNULL(memccpy(buf, s, '\0', sizeof(buf))); + * char buf[16]; + * CHECK_NOTNULL(memccpy(buf, s, '\0', sizeof(buf))); * * Or unstrictly: * - * if (!memccpy(buf, s, '\0', sizeof(buf))) strcpy(buf, "?"); + * if (!memccpy(buf, s, '\0', sizeof(buf))) strcpy(buf, "?"); * * Are usually more sensible than the following: * - * char cstrbuf[16]; - * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); + * char cstrbuf[16]; + * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); * * @return 𝑑 + idx(𝑐) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ * @note 𝑑 and 𝑠 can't overlap diff --git a/libc/str/stpncpy.c b/libc/str/stpncpy.c index 41f17de0e..ef7501d61 100644 --- a/libc/str/stpncpy.c +++ b/libc/str/stpncpy.c @@ -23,6 +23,7 @@ * Prepares static search buffer. * * 1. If SRC is too long, it's truncated and *not* NUL-terminated. + * * 2. If SRC is too short, the remainder is zero-filled. * * Please note this function isn't designed to prevent untrustworthy diff --git a/libc/str/strncpy.c b/libc/str/strncpy.c index 91ee84577..a249aa40b 100644 --- a/libc/str/strncpy.c +++ b/libc/str/strncpy.c @@ -23,6 +23,7 @@ * Prepares static search buffer. * * 1. If SRC is too long, it's truncated and *not* NUL-terminated. + * * 2. If SRC is too short, the remainder is zero-filled. * * Please note this function isn't designed to prevent untrustworthy diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index ae40f7a18..7292dd3ac 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -46,7 +46,7 @@ wontreturn void testlib_abort(void) { */ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end, testfn_t warmup) { - /** + /* * getpid() calls are inserted to help visually see tests in traces * which can be performed on Linux, FreeBSD, OpenBSD, and XNU: * diff --git a/libc/time/strftime.c b/libc/time/strftime.c index b52083dc7..d9f7933d3 100644 --- a/libc/time/strftime.c +++ b/libc/time/strftime.c @@ -370,13 +370,13 @@ static char *strftime_timefmt(char *p, const char *pe, const char *format, /** * Converts time to string, e.g. * - * char b[64]; - * int64_t sec; - * struct tm tm; - * time(&sec); - * localtime_r(&sec, &tm); - * strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601 - * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 + * char b[64]; + * int64_t sec; + * struct tm tm; + * time(&sec); + * localtime_r(&sec, &tm); + * strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601 + * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 * * @return bytes copied excluding nul, or 0 on error */ diff --git a/libc/unicode/strnwidth.c b/libc/unicode/strnwidth.c index 46b8b60fb..dd28be0f9 100644 --- a/libc/unicode/strnwidth.c +++ b/libc/unicode/strnwidth.c @@ -25,7 +25,9 @@ * Returns monospace display width of UTF-8 string. * * - Control codes are discounted + * * - ANSI escape sequences are discounted + * * - East asian glyphs, emoji, etc. count as two * * @param s is NUL-terminated string diff --git a/libc/x/unbingbuf.c b/libc/x/unbingbuf.c index 05bb49c55..9b63f1923 100644 --- a/libc/x/unbingbuf.c +++ b/libc/x/unbingbuf.c @@ -27,10 +27,10 @@ /** * Decodes human-readable CP437 glyphs into binary, e.g. * - * char binged[5]; - * char golden[5] = "\0\1\2\3\4"; - * unbingbuf(binged, sizeof(binged), u" ☺☻♥♦", -1); - * CHECK_EQ(0, memcmp(binged, golden, 5)); + * char binged[5]; + * char golden[5] = "\0\1\2\3\4"; + * unbingbuf(binged, sizeof(binged), u" ☺☻♥♦", -1); + * CHECK_EQ(0, memcmp(binged, golden, 5)); * * @param buf is caller owned * @param size is byte length of buf diff --git a/libc/x/unbingstr.c b/libc/x/unbingstr.c index 1ff46cfae..e19d2c628 100644 --- a/libc/x/unbingstr.c +++ b/libc/x/unbingstr.c @@ -24,7 +24,7 @@ /** * Decodes human-readable CP437 glyphs into binary, e.g. * - * CHECK_EQ(0, memcmp(gc(unbingstr(u" ☺☻♥♦")), "\0\1\2\3\4", 5)); + * CHECK_EQ(0, memcmp(gc(unbingstr(u" ☺☻♥♦")), "\0\1\2\3\4", 5)); * * @param buf is caller owned * @param size is byte length of buf diff --git a/libc/x/xjoinpaths.c b/libc/x/xjoinpaths.c index dac89ba13..92cb74cbf 100644 --- a/libc/x/xjoinpaths.c +++ b/libc/x/xjoinpaths.c @@ -24,12 +24,12 @@ /** * Joins paths, e.g. * - * "a" + "b" → "a/b" - * "a/" + "b" → "a/b" - * "a" + "b/" → "a/b/" - * "a" + "/b" → "/b" - * "." + "b" → "b" - * "" + "b" → "b" + * "a" + "b" → "a/b" + * "a/" + "b" → "a/b" + * "a" + "b/" → "a/b/" + * "a" + "/b" → "/b" + * "." + "b" → "b" + * "" + "b" → "b" * * @return newly allocated string of resulting path */ diff --git a/libc/x/xsigaction.c b/libc/x/xsigaction.c index d6555f395..eeabbe3ee 100644 --- a/libc/x/xsigaction.c +++ b/libc/x/xsigaction.c @@ -26,8 +26,8 @@ /** * Installs handler for kernel interrupt, e.g.: * - * onctrlc(sig) { exit(128+sig); } - * CHECK_NE(-1, xsigaction(SIGINT, onctrlc, SA_RESETHAND, 0, 0)); + * onctrlc(sig) { exit(128+sig); } + * CHECK_NE(-1, xsigaction(SIGINT, onctrlc, SA_RESETHAND, 0, 0)); * * @param sig can be SIGINT, SIGTERM, etc. * @param handler is SIG_DFL, SIG_IGN, or a pointer to a 0≤arity≤3 diff --git a/test/libc/nexgen32e/ffs_test.c b/test/libc/nexgen32e/ffs_test.c new file mode 100644 index 000000000..e3195e62a --- /dev/null +++ b/test/libc/nexgen32e/ffs_test.c @@ -0,0 +1,45 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/nexgen32e/ffs.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/testlib/testlib.h" + +TEST(ffs, test) { + EXPECT_EQ(__builtin_ffs(0), (ffs)(0)); + EXPECT_EQ(__builtin_ffs(1), (ffs)(1)); + EXPECT_EQ(__builtin_ffs(0x00100000), (ffs)(0x00100000)); + EXPECT_EQ(__builtin_ffs(-1), (ffs)(-1)); +} + +TEST(ffsl, test) { + EXPECT_EQ(__builtin_ffsl(0), (ffsl)(0)); + EXPECT_EQ(__builtin_ffsl(1), (ffsl)(1)); + EXPECT_EQ(__builtin_ffsl(0x00100000), (ffsl)(0x00100000)); + EXPECT_EQ(__builtin_ffsl(0x0010000000000000), (ffsl)(0x0010000000000000)); + EXPECT_EQ(__builtin_ffsl(-1), (ffsl)(-1)); +} + +TEST(ffsll, test) { + EXPECT_EQ(__builtin_ffsll(0), (ffsll)(0)); + EXPECT_EQ(__builtin_ffsll(1), (ffsll)(1)); + EXPECT_EQ(__builtin_ffsll(0x00100000), (ffsll)(0x00100000)); + EXPECT_EQ(__builtin_ffsll(0x0010000000000000), (ffsll)(0x0010000000000000)); + EXPECT_EQ(__builtin_ffsll(-1), (ffsll)(-1)); +} diff --git a/test/tool/build/lib/javadown_test.c b/test/tool/build/lib/javadown_test.c new file mode 100644 index 000000000..db531d5df --- /dev/null +++ b/test/tool/build/lib/javadown_test.c @@ -0,0 +1,230 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/runtime/gc.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/testlib/testlib.h" +#include "tool/build/lib/javadown.h" + +TEST(ParseJavadown, testOneLiner) { + const char *comment = "/** Parses javadown. */"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("", jd->text); + EXPECT_EQ(0, jd->tags.n); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testShortAndTerse) { + const char *comment = "\ +/**\n\ + * Parses javadown.\n\ + * @see love\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("", jd->text); + EXPECT_EQ(1, jd->tags.n); + EXPECT_STREQ("see", jd->tags.p[0].tag); + EXPECT_STREQ("love", jd->tags.p[0].text); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testBlankLineOmitted) { + const char *comment = "\ +/**\n\ + * Parses javadown.\n\ + *\n\ + * Description.\n\ + * @see love\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("Description.", jd->text); + EXPECT_EQ(1, jd->tags.n); + EXPECT_STREQ("see", jd->tags.p[0].tag); + EXPECT_STREQ("love", jd->tags.p[0].text); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testContentInterpretation) { + const char *comment = "\ +/**\n\ + * Parses javadown \n\ + * and that is the bottom line.\n\ + *\n\ + * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ + * eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ + * ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ + * aliquip ex ea commodo consequat.\n\ + *\n\ + * Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ + * dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ + * non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ + * laborum\n\ + *\n\ + * @param data should point to text inside the slash star markers\n\ + * lorem ipsum dolla dollaz yo\n\ + * @param size is length of data in bytes\n\ + * @return object that should be passed to FreeJavadown()\n\ + * @asyncsignalsafe\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +aliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testTabFormatting1) { + const char *comment = "\ +/**\n\ +\tParses javadown \n\ +\tand that is the bottom line.\n\ +\n\ +\tLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ +\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\taliquip ex ea commodo consequat.\n\ +\n\ +\tDuis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +\tdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +\tnon proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +\tlaborum\n\ +\n\ +\t@param data should point to text inside the slash star markers\n\ +\t\tlorem ipsum dolla dollaz yo\n\ +\t@param size is length of data in bytes\n\ +\t@return object that should be passed to FreeJavadown()\n\ +\t@asyncsignalsafe\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +aliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testTabFormatting2) { + const char *comment = "\ +/**\n\ +\tParses javadown \n\ +\tand that is the bottom line.\n\ +\t\n\ +\tLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\t\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ +\t\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\t\taliquip ex ea commodo consequat.\n\ +\t\n\ +\tDuis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +\tdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +\tnon proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +\tlaborum\n\ +\t\n\ +\t@param data should point to text inside the slash star markers\n\ +\t\tlorem ipsum dolla dollaz yo\n\ +\t@param size is length of data in bytes\n\ +\t@return object that should be passed to FreeJavadown()\n\ +\t@asyncsignalsafe\n\ +*/"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\taliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo index 56971eecc..bb5ce109c 100644 --- a/third_party/chibicc/README.cosmo +++ b/third_party/chibicc/README.cosmo @@ -16,18 +16,22 @@ local enhancements - support __builtin_constant_p, __builtin_likely, etc. - support __builtin_isunordered, __builtin_islessgreater, etc. - support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc. +- support __force_align_arg_pointer__, __no_caller_saved_registers__, etc. - support __constructor__, __section__, __cold__, -ffunction-sections, etc. - support building -x assembler-with-cpp a.k.a. .S files - support profiling w/ -mcount / -mfentry / -mnop-mcount - improve error messages to trace macro expansions - reduce #lines of generated assembly by a third - reduce #bytes of generated binary by a third +- report divide errors in constexprs local bug fixes - allow casted values to be lvalues +- permit remainder operator in constexprs - permit parentheses around string-initializer - fix 64-bit bug in generated code for struct bitfields +- fix struct_designator() so it won't crash on anonymous union members - fix bug where last statement in statement expression couldn't have label - print_tokens (chibicc -E) now works in the case of adjacent string literals - make enums unsigned (like gcc) so we don't suffer the msvc enum bitfield bug @@ -35,6 +39,8 @@ local bug fixes local changes - use tabs in generated output +- parse javadoc-style markdown comments +- don't fold backslash newline in comments - generated code no longer assumes red zone - emit .size directives for function definitions - use fisttp long double conversions if built w/ -msse3 diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 6a6133d98..4d06bb623 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -177,8 +177,8 @@ struct As { struct Sauces { unsigned long n; struct Sauce { - int path; // strings - int line; // 1-indexed + unsigned path; // strings + unsigned line; // 1-indexed } * p; } sauces; struct Things { @@ -192,14 +192,14 @@ struct As { TT_FORWARD, TT_BACKWARD, } t : 4; - int s : 28; // sauces - int i; // identity,ints,floats,slices + unsigned s : 28; // sauces + unsigned i; // identity,ints,floats,slices } * p; } things; struct Sections { unsigned long n; struct Section { - int name; // strings + unsigned name; // strings int flags; int type; int align; @@ -210,11 +210,11 @@ struct As { unsigned long n; struct Symbol { bool isused; - int name; // slices - int section; // sections - int stb; // STB_* - int stv; // STV_* - int type; // STT_* + unsigned char stb; // STB_* + unsigned char stv; // STV_* + unsigned char type; // STT_* + unsigned name; // slices + unsigned section; // sections long offset; long size; struct ElfWriterSymRef ref; @@ -223,25 +223,25 @@ struct As { struct HashTable { unsigned i, n; struct HashEntry { - int h; - int i; + unsigned h; + unsigned i; } * p; } symbolindex; struct Labels { unsigned long n; struct Label { - int id; - int tok; // things - int symbol; // symbols + unsigned id; + unsigned tok; // things + unsigned symbol; // symbols } * p; } labels; struct Relas { unsigned long n; struct Rela { bool isdead; - int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} - int expr; // exprs - int section; // sections + int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} + unsigned expr; // exprs + unsigned section; // sections long offset; long addend; } * p; @@ -251,7 +251,7 @@ struct As { struct Expr { enum ExprKind { EX_INT, // integer - EX_SYM, // slice, forward, backward, then symbol + EX_SYM, // things (then symbols after eval) EX_NEG, // unary - EX_NOT, // unary ! EX_BITNOT, // unary ~ @@ -276,7 +276,7 @@ struct As { EM_DTPOFF, EM_TPOFF, } em; - int tok; + unsigned tok; int lhs; int rhs; long x; @@ -456,7 +456,7 @@ static bool EndsWith(const char *s, const char *suffix) { n = strlen(s); m = strlen(suffix); if (m > n) return false; - return memcmp(s + n - m, suffix, m) == 0; + return !memcmp(s + n - m, suffix, m); } static char *Format(const char *fmt, ...) { @@ -1192,21 +1192,21 @@ static int ParseMul(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '*')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x *= a->exprs.p[y].x; } else { x = NewBinary(a, EX_MUL, x, y); } } else if (IsPunct(a, i, '/')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x /= a->exprs.p[y].x; } else { x = NewBinary(a, EX_DIV, x, y); } } else if (IsPunct(a, i, '%')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x %= a->exprs.p[y].x; } else { x = NewBinary(a, EX_REM, x, y); @@ -1225,14 +1225,14 @@ static int ParseAdd(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '+')) { y = ParseMul(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x += a->exprs.p[y].x; } else { x = NewBinary(a, EX_ADD, x, y); } } else if (IsPunct(a, i, '-')) { y = ParseMul(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x -= a->exprs.p[y].x; } else if (a->exprs.p[y].kind == EX_INT) { a->exprs.p[y].x = -a->exprs.p[y].x; @@ -1254,14 +1254,14 @@ static int ParseShift(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '<' << 8 | '<')) { y = ParseAdd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x <<= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHL, x, y); } } else if (IsPunct(a, i, '>' << 8 | '>')) { y = ParseAdd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x >>= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHR, x, y); @@ -1280,28 +1280,28 @@ static int ParseRelational(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '<')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x < a->exprs.p[y].x; } else { x = NewBinary(a, EX_LT, x, y); } } else if (IsPunct(a, i, '>')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x < a->exprs.p[x].x; } else { x = NewBinary(a, EX_LT, y, x); } } else if (IsPunct(a, i, '<' << 8 | '=')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x <= a->exprs.p[y].x; } else { x = NewBinary(a, EX_LE, x, y); } } else if (IsPunct(a, i, '>' << 8 | '=')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x <= a->exprs.p[x].x; } else { x = NewBinary(a, EX_LE, y, x); @@ -1320,14 +1320,14 @@ static int ParseEquality(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '=' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x; } else { x = NewBinary(a, EX_EQ, x, y); } } else if (IsPunct(a, i, '!' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x; } else { x = NewBinary(a, EX_NE, x, y); @@ -1346,7 +1346,7 @@ static int ParseAnd(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '&')) { y = ParseEquality(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x &= a->exprs.p[y].x; } else { x = NewBinary(a, EX_AND, x, y); @@ -1365,7 +1365,7 @@ static int ParseXor(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '^')) { y = ParseAnd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x ^= a->exprs.p[y].x; } else { x = NewBinary(a, EX_XOR, x, y); @@ -1384,7 +1384,7 @@ static int ParseOr(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '|')) { y = ParseXor(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x |= a->exprs.p[y].x; } else { x = NewBinary(a, EX_OR, x, y); @@ -3745,8 +3745,7 @@ static int ResolveSymbol(struct As *a, int i) { case TT_FORWARD: return FindLabelForward(a, a->ints.p[a->things.p[i].i]); default: - DebugBreak(); - Fail(a, "this corruption"); + Fail(a, "this corruption %d", a->things.p[i].t); } } @@ -3777,15 +3776,6 @@ static void Write32(char b[4], int x) { b[3] = x >> 030; } -static void MarkUndefinedSymbolsGlobal(struct As *a) { - int i; - for (i = 0; i < a->symbols.n; ++i) { - if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) { - a->symbols.p[i].stb = STB_GLOBAL; - } - } -} - static void MarkUsedSymbols(struct As *a, int i) { if (i == -1) return; MarkUsedSymbols(a, a->exprs.p[i].lhs); @@ -3818,6 +3808,16 @@ static void Evaluate(struct As *a) { } } +static void MarkUndefinedSymbolsGlobal(struct As *a) { + int i; + for (i = 0; i < a->symbols.n; ++i) { + if (a->symbols.p[i].isused && !a->symbols.p[i].section && + a->symbols.p[i].stb == STB_LOCAL) { + a->symbols.p[i].stb = STB_GLOBAL; + } + } +} + static bool IsLocal(struct As *a, int name) { if (name < 0) return true; return a->slices.p[name].n >= 2 && !memcmp(a->slices.p[name].p, ".L", 2); @@ -3829,17 +3829,18 @@ static bool IsLiveSymbol(struct As *a, int i) { } static void Objectify(struct As *a, int path) { - int i, j, s; + char *p; + int i, j, s, e; struct ElfWriter *elf; elf = elfwriter_open(a->strings.p[path], 0644); for (i = 0; i < a->symbols.n; ++i) { if (!IsLiveSymbol(a, i)) continue; + p = strndup(a->slices.p[a->symbols.p[i].name].p, + a->slices.p[a->symbols.p[i].name].n); a->symbols.p[i].ref = elfwriter_appendsym( - elf, - strndup(a->slices.p[a->symbols.p[i].name].p, - a->slices.p[a->symbols.p[i].name].n), - ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type), + elf, p, ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type), a->symbols.p[i].stv, a->symbols.p[i].offset, a->symbols.p[i].size); + free(p); } for (i = 0; i < a->sections.n; ++i) { elfwriter_align(elf, a->sections.p[i].align, 0); @@ -3853,24 +3854,24 @@ static void Objectify(struct As *a, int path) { for (j = 0; j < a->relas.n; ++j) { if (a->relas.p[j].isdead) continue; if (a->relas.p[j].section != i) continue; - a->i = a->exprs.p[a->relas.p[j].expr].tok; - switch (a->exprs.p[a->relas.p[j].expr].kind) { + e = a->relas.p[j].expr; + a->i = a->exprs.p[e].tok; + switch (a->exprs.p[e].kind) { case EX_INT: break; case EX_SYM: - elfwriter_appendrela( - elf, a->relas.p[j].offset, - a->symbols.p[a->exprs.p[a->relas.p[j].expr].x].ref, - a->relas.p[j].kind, a->relas.p[j].addend); + elfwriter_appendrela(elf, a->relas.p[j].offset, + a->symbols.p[a->exprs.p[e].x].ref, + a->relas.p[j].kind, a->relas.p[j].addend); break; case EX_ADD: - if (a->exprs.p[a->exprs.p[j].lhs].kind == EX_SYM && - a->exprs.p[a->exprs.p[j].rhs].kind == EX_INT) { + if (a->exprs.p[a->exprs.p[e].lhs].kind == EX_SYM && + a->exprs.p[a->exprs.p[e].rhs].kind == EX_INT) { elfwriter_appendrela( elf, a->relas.p[j].offset, - a->symbols.p[a->exprs.p[a->exprs.p[j].lhs].x].ref, + a->symbols.p[a->exprs.p[a->exprs.p[e].lhs].x].ref, a->relas.p[j].kind, - a->relas.p[j].addend + a->exprs.p[a->exprs.p[j].rhs].x); + a->relas.p[j].addend + a->exprs.p[a->exprs.p[e].rhs].x); } else { Fail(a, "bad addend"); } @@ -3887,6 +3888,58 @@ static void Objectify(struct As *a, int path) { elfwriter_close(elf); } +static void CheckIntegrity(struct As *a) { + int i; + for (i = 0; i < a->things.n; ++i) { + CHECK_LT((int)a->things.p[i].s, a->sauces.n); + switch (a->things.p[i].t) { + case TT_INT: + case TT_FORWARD: + case TT_BACKWARD: + CHECK_LT(a->things.p[i].i, a->ints.n); + break; + case TT_FLOAT: + CHECK_LT(a->things.p[i].i, a->floats.n); + break; + case TT_SLICE: + CHECK_LT(a->things.p[i].i, a->slices.n); + break; + default: + break; + } + } + for (i = 0; i < a->sections.n; ++i) { + CHECK_LT(a->sections.p[i].name, a->strings.n); + } + for (i = 0; i < a->symbols.n; ++i) { + CHECK_LT(a->symbols.p[i].name, a->slices.n); + CHECK_LT(a->symbols.p[i].section, a->sections.n); + } + for (i = 0; i < a->labels.n; ++i) { + CHECK_LT(a->labels.p[i].tok, a->things.n); + CHECK_LT(a->labels.p[i].symbol, a->symbols.n); + } + for (i = 0; i < a->relas.n; ++i) { + CHECK_LT(a->relas.p[i].expr, a->exprs.n); + CHECK_LT(a->relas.p[i].section, a->sections.n); + } + for (i = 0; i < a->exprs.n; ++i) { + CHECK_LT(a->exprs.p[i].tok, a->things.n); + if (a->exprs.p[i].lhs != -1) CHECK_LT(a->exprs.p[i].lhs, a->exprs.n); + if (a->exprs.p[i].rhs != -1) CHECK_LT(a->exprs.p[i].rhs, a->exprs.n); + switch (a->exprs.p[i].kind) { + case EX_SYM: + CHECK_LT(a->exprs.p[i].x, a->things.n); + CHECK(a->things.p[a->exprs.p[i].x].t == TT_SLICE || + a->things.p[a->exprs.p[i].x].t == TT_FORWARD || + a->things.p[a->exprs.p[i].x].t == TT_BACKWARD); + break; + default: + break; + } + } +} + static void PrintThings(struct As *a) { int i; char pbuf[4], fbuf[32]; @@ -3929,17 +3982,18 @@ void Assembler(int argc, char *argv[]) { Tokenize(a, a->inpath); /* PrintThings(a); */ Assemble(a); + /* CheckIntegrity(a); */ Evaluate(a); MarkUndefinedSymbolsGlobal(a); Objectify(a, a->outpath); - malloc_stats(); + /* malloc_stats(); */ FreeAssembler(a); } int main(int argc, char *argv[]) { showcrashreports(); if (argc == 1) { - system("o//third_party/chibicc/as.com -o /tmp/o third_party/chibicc/hog.s"); + system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s"); system("objdump -xwd /tmp/o"); exit(0); } diff --git a/third_party/chibicc/chibicc.c b/third_party/chibicc/chibicc.c index 829267db0..fd6ce4ddf 100644 --- a/third_party/chibicc/chibicc.c +++ b/third_party/chibicc/chibicc.c @@ -32,6 +32,7 @@ bool opt_verbose; static bool opt_A; static bool opt_E; +static bool opt_J; static bool opt_M; static bool opt_MD; static bool opt_MMD; @@ -202,6 +203,8 @@ static void parse_args(int argc, char **argv) { opt_c = true; } else if (!strcmp(argv[i], "-E")) { opt_E = true; + } else if (!strcmp(argv[i], "-J")) { + opt_J = true; } else if (!strcmp(argv[i], "-A")) { opt_A = true; } else if (!strcmp(argv[i], "-I")) { @@ -364,7 +367,14 @@ static char *create_tmpfile(void) { return path; } -static void run_subprocess(char **argv) { +static void handle_exit(bool ok) { + if (!ok) { + opt_save_temps = true; + exit(1); + } +} + +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]); @@ -384,13 +394,10 @@ static void run_subprocess(char **argv) { break; } } - if (status != 0) { - opt_save_temps = true; - exit(1); - } + return !status; } -static void run_cc1(int argc, char **argv, char *input, char *output) { +static bool run_cc1(int argc, char **argv, char *input, char *output) { char **args = calloc(argc + 10, sizeof(char *)); memcpy(args, argv, argc * sizeof(char *)); args[argc++] = "-cc1"; @@ -402,7 +409,7 @@ static void run_cc1(int argc, char **argv, char *input, char *output) { args[argc++] = "-cc1-output"; args[argc++] = output; } - run_subprocess(args); + return run_subprocess(args); } static void print_token(FILE *out, Token *tok) { @@ -540,6 +547,10 @@ static void cc1(void) { print_ast(stdout, prog); return; } + if (opt_J) { + output_javadown(output_file, prog); + return; + } FILE *out = open_file(output_file); codegen(prog, out); fclose(out); @@ -561,7 +572,7 @@ static void assemble(char *input, char *output) { strarray_push(&arr, "-o"); strarray_push(&arr, output); strarray_push(&arr, NULL); - run_subprocess(arr.data); + handle_exit(run_subprocess(arr.data)); } static void run_linker(StringArray *inputs, char *output) { @@ -591,7 +602,7 @@ static void run_linker(StringArray *inputs, char *output) { strarray_push(&arr, inputs->data[i]); } strarray_push(&arr, NULL); - run_subprocess(arr.data); + handle_exit(run_subprocess(arr.data)); } int chibicc(int argc, char **argv) { @@ -608,6 +619,7 @@ int chibicc(int argc, char **argv) { error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files"); } StringArray ld_args = {}; + StringArray dox_args = {}; for (int i = 0; i < input_paths.len; i++) { char *input = input_paths.data[i]; if (!strncmp(input, "-l", 2)) { @@ -647,25 +659,33 @@ int chibicc(int argc, char **argv) { assert(type == FILE_C || type == FILE_ASM_CPP); // Just preprocess if (opt_E || opt_M) { - run_cc1(argc, argv, input, NULL); + handle_exit(run_cc1(argc, argv, input, NULL)); continue; } // Compile if (opt_S) { - run_cc1(argc, argv, input, output); + handle_exit(run_cc1(argc, argv, input, output)); continue; } // Compile and assemble if (opt_c) { char *tmp = create_tmpfile(); - run_cc1(argc, argv, input, tmp); + handle_exit(run_cc1(argc, argv, input, tmp)); assemble(tmp, output); continue; } + // Dox + if (opt_J) { + char *tmp = create_tmpfile(); + if (run_cc1(argc, argv, input, tmp)) { + strarray_push(&dox_args, tmp); + } + continue; + } // Compile, assemble and link char *tmp1 = create_tmpfile(); char *tmp2 = create_tmpfile(); - run_cc1(argc, argv, input, tmp1); + handle_exit(run_cc1(argc, argv, input, tmp1)); assemble(tmp1, tmp2); strarray_push(&ld_args, tmp2); continue; @@ -673,5 +693,8 @@ int chibicc(int argc, char **argv) { if (ld_args.len > 0) { run_linker(&ld_args, opt_o ? opt_o : "a.out"); } + if (dox_args.len > 0) { + drop_dox(&dox_args, opt_o ? opt_o : "/dev/stdout"); + } return 0; } diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 86df1cda0..0e355049c 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -26,6 +26,7 @@ #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" +#include "tool/build/lib/javadown.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -35,7 +36,10 @@ typedef struct Asm Asm; typedef struct AsmOperand AsmOperand; typedef struct File File; typedef struct FpClassify FpClassify; +typedef struct HashMap HashMap; typedef struct Hideset Hideset; +typedef struct Macro Macro; +typedef struct MacroParam MacroParam; typedef struct Member Member; typedef struct Node Node; typedef struct Obj Obj; @@ -47,6 +51,8 @@ typedef struct Token Token; typedef struct TokenStack TokenStack; typedef struct Type Type; +typedef Token *macro_handler_fn(Token *); + // // strarray.c // @@ -64,13 +70,14 @@ void strarray_push(StringArray *, char *); // typedef enum { - TK_IDENT, // Identifiers - TK_PUNCT, // Punctuators - TK_KEYWORD, // Keywords - TK_STR, // String literals - TK_NUM, // Numeric literals - TK_PP_NUM, // Preprocessing numbers - TK_EOF, // End-of-file markers + TK_IDENT, // Identifiers + TK_PUNCT, // Punctuators + TK_KEYWORD, // Keywords + TK_STR, // String literals + TK_NUM, // Numeric literals + TK_PP_NUM, // Preprocessing numbers + TK_JAVADOWN, // /** ... */ comments + TK_EOF, // End-of-file markers } TokenKind; struct File { @@ -80,6 +87,7 @@ struct File { // For #line directive char *display_name; int line_delta; + struct Javadown *javadown; }; struct thatispacked Token { @@ -96,6 +104,7 @@ struct thatispacked Token { char *filename; // Filename Hideset *hideset; // For macro expansion Token *origin; // If this is expanded from a macro, the original token + struct Javadown *javadown; union { int64_t val; // If kind is TK_NUM, its value long double fval; // If kind is TK_NUM, its value @@ -134,6 +143,23 @@ int read_escaped_char(char **, char *); // preprocess.c // +struct MacroParam { + MacroParam *next; + char *name; +}; + +struct Macro { + char *name; + bool is_objlike; // Object-like or function-like + MacroParam *params; + char *va_args_name; + Token *body; + macro_handler_fn *handler; + Token *javadown; +}; + +extern HashMap macros; + char *search_include_paths(char *); void init_macros(void); void define_macro(char *, char *); @@ -232,6 +258,7 @@ struct Obj { char *asmname; char *section; char *visibility; + Token *javadown; // Global variable bool is_tentative; bool is_string_literal; @@ -244,6 +271,9 @@ struct Obj { bool is_noreturn; bool is_destructor; bool is_constructor; + bool is_ms_abi; /* TODO */ + bool is_force_align_arg_pointer; + bool is_no_caller_saved_registers; int stack_size; Obj *params; Node *body; @@ -419,6 +449,7 @@ struct Type { int align; // alignment bool is_unsigned; // unsigned or signed bool is_atomic; // true if _Atomic + bool is_ms_abi; // microsoft abi 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. @@ -534,11 +565,11 @@ typedef struct { void *val; } HashEntry; -typedef struct { +struct HashMap { HashEntry *buckets; int capacity; int used; -} HashMap; +}; void *hashmap_get(HashMap *, char *); void *hashmap_get2(HashMap *, char *, int); @@ -584,6 +615,13 @@ Token *alloc_token(void); Obj *alloc_obj(void); Type *alloc_type(void); +// +// javadown.c +// + +void output_javadown(const char *, Obj *); +void drop_dox(const StringArray *, const char *); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 67d0bd19b..a3b7c1329 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -49,6 +49,7 @@ THIRD_PARTY_CHIBICC_A_CHECKS = \ $(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok) THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ + LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ LIBC_CALLS_HEFTY \ diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index 658cf35cb..608c72f3a 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -2265,7 +2265,7 @@ static void emit_data(Obj *prog) { } } -static void store_fp(int r, int offset, int sz) { +static void store_fp(Obj *fn, int r, int offset, int sz) { switch (sz) { case 4: println("\tmovss\t%%xmm%d,%d(%%rbp)", r, offset); @@ -2274,7 +2274,8 @@ static void store_fp(int r, int offset, int sz) { println("\tmovsd\t%%xmm%d,%d(%%rbp)", r, offset); return; case 16: - println("\tmovaps\t%%xmm%d,%d(%%rbp)", r, offset); + println("\t%s\t%%xmm%d,%d(%%rbp)", + fn->is_force_align_arg_pointer ? "movups" : "movaps", r, offset); return; } UNREACHABLE(); @@ -2381,13 +2382,13 @@ static void emit_text(Obj *prog) { case TY_UNION: assert(ty->size <= 16); if (has_flonum(ty, 0, 8, 0)) { - store_fp(fp++, var->offset, MIN(8, ty->size)); + store_fp(fn, fp++, var->offset, MIN(8, ty->size)); } else { store_gp(gp++, var->offset, MIN(8, ty->size)); } if (ty->size > 8) { if (has_flonum(ty, 8, 16, 0)) { - store_fp(fp++, var->offset + 8, ty->size - 8); + store_fp(fn, fp++, var->offset + 8, ty->size - 8); } else { store_gp(gp++, var->offset + 8, ty->size - 8); } @@ -2395,7 +2396,7 @@ static void emit_text(Obj *prog) { break; case TY_FLOAT: case TY_DOUBLE: - store_fp(fp++, var->offset, ty->size); + store_fp(fn, fp++, var->offset, ty->size); break; case TY_INT128: store_gp(gp++, var->offset + 0, 8); @@ -2405,6 +2406,20 @@ static void emit_text(Obj *prog) { store_gp(gp++, var->offset, ty->size); } } + if (fn->is_force_align_arg_pointer) { + emitlin("\tand\t$-16,%rsp"); + } + if (fn->is_no_caller_saved_registers) { + emitlin("\ +\tpush\t%rdi\n\ +\tpush\t%rsi\n\ +\tpush\t%rdx\n\ +\tpush\t%rcx\n\ +\tpush\t%r8\n\ +\tpush\t%r9\n\ +\tpush\t%r10\n\ +\tpush\t%r11"); + } // Emit code gen_stmt(fn->body); assert(!depth); @@ -2420,6 +2435,17 @@ static void emit_text(Obj *prog) { if (fn->is_noreturn) { emitlin("\tud2"); } else { + if (fn->is_no_caller_saved_registers) { + emitlin("\ +\tpop\t%r11\n\ +\tpop\t%r10\n\ +\tpop\t%r9\n\ +\tpop\t%r8\n\ +\tpop\t%rcx\n\ +\tpop\t%rdx\n\ +\tpop\t%rsi\n\ +\tpop\t%rdi"); + } emitlin("\tleave"); emitlin("\tret"); } diff --git a/third_party/chibicc/dox1.c b/third_party/chibicc/dox1.c new file mode 100644 index 000000000..a625d4bc3 --- /dev/null +++ b/third_party/chibicc/dox1.c @@ -0,0 +1,248 @@ +/*-*- 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/runtime/gc.h" +#include "third_party/chibicc/chibicc.h" + +#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) + +struct DoxWriter { + struct Buffer { + size_t n; + char *p; + } buf; + struct Macros { + size_t n; + Macro **p; + } macros; + struct Objects { + size_t n; + Obj **p; + } objects; +}; + +static void SerializeData(struct Buffer *buf, const void *p, unsigned long n) { + struct Slice *s; + buf->p = realloc(buf->p, buf->n + n); + memcpy(buf->p + buf->n, p, n); + buf->n += n; +} + +static int SerializeInt(struct Buffer *buf, int x) { + unsigned char b[4]; + b[0] = x >> 000; + b[1] = x >> 010; + b[2] = x >> 020; + b[3] = x >> 030; + SerializeData(buf, b, 4); + return x; +} + +static void SerializeStr(struct Buffer *buf, const char *s) { + size_t n; + if (!s) s = ""; + n = strlen(s); + n = MIN(INT_MAX, n); + SerializeInt(buf, n); + SerializeData(buf, s, n); +} + +static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) { + int i; + SerializeInt(buf, jd->isfileoverview); + SerializeStr(buf, jd->title); + SerializeStr(buf, jd->text); + SerializeInt(buf, jd->tags.n); + for (i = 0; i < jd->tags.n; ++i) { + SerializeStr(buf, jd->tags.p[i].tag); + SerializeStr(buf, jd->tags.p[i].text); + } +} + +static char *DescribeScalar(struct Type *ty, char *name) { + return xasprintf("%s%s%s", ty->is_atomic ? "_Atomic " : "", + ty->is_unsigned ? "unsigned " : "", name); +} + +static char *DescribeType(struct Type *ty) { + switch (ty->kind) { + case TY_VOID: + return strdup("void"); + case TY_BOOL: + return strdup("_Bool"); + case TY_CHAR: + return DescribeScalar(ty, "char"); + case TY_SHORT: + return DescribeScalar(ty, "short"); + case TY_INT: + return DescribeScalar(ty, "int"); + case TY_LONG: + return DescribeScalar(ty, "long"); + case TY_INT128: + return DescribeScalar(ty, "__int128"); + case TY_FLOAT: + return DescribeScalar(ty, "float"); + case TY_DOUBLE: + return DescribeScalar(ty, "double"); + case TY_LDOUBLE: + return DescribeScalar(ty, "long double"); + case TY_PTR: + return xasprintf("%s*", gc(DescribeType(ty->base))); + case TY_ARRAY: + return xasprintf("%s[%d]", gc(DescribeType(ty->base)), ty->array_len); + case TY_ENUM: + if (ty->name_pos) { + return xasprintf("enum %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-ENUM"); + } + case TY_STRUCT: + if (ty->name_pos) { + return xasprintf("struct %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-STRUCT"); + } + case TY_UNION: + if (ty->name_pos) { + return xasprintf("union %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-UNION"); + } + case TY_FUNC: + return xasprintf("%s(*)()", gc(DescribeType(ty->return_ty))); + default: + return "UNKNOWN"; + } +} + +static int CountParams(Obj *params) { + int n; + for (n = 0; params; params = params->next) ++n; + return n; +} + +static const char *GetFileName(Obj *obj) { + if (obj->javadown && obj->javadown->file) return obj->javadown->file->name; + if (obj->tok && obj->tok->file) return obj->tok->file->name; + return "missingno.c"; +} + +static int GetLine(Obj *obj) { + if (obj->javadown && obj->javadown->file) return obj->javadown->line_no; + if (obj->tok && obj->tok->file) return obj->tok->line_no; + return 0; +} + +static void SerializeDox(struct DoxWriter *dox, Obj *prog) { + int i; + char *s; + Obj *param; + MacroParam *mparam; + SerializeInt(&dox->buf, dox->objects.n); + for (i = 0; i < dox->objects.n; ++i) { + s = DescribeType(dox->objects.p[i]->ty); + SerializeStr(&dox->buf, s); + free(s); + SerializeStr(&dox->buf, dox->objects.p[i]->name); + SerializeStr(&dox->buf, GetFileName(dox->objects.p[i])); + SerializeInt(&dox->buf, GetLine(dox->objects.p[i])); + SerializeInt(&dox->buf, dox->objects.p[i]->is_function); + SerializeInt(&dox->buf, dox->objects.p[i]->is_weak); + SerializeInt(&dox->buf, dox->objects.p[i]->is_inline); + SerializeInt(&dox->buf, dox->objects.p[i]->is_noreturn); + SerializeInt(&dox->buf, dox->objects.p[i]->is_destructor); + SerializeInt(&dox->buf, dox->objects.p[i]->is_constructor); + SerializeInt(&dox->buf, dox->objects.p[i]->is_force_align_arg_pointer); + SerializeInt(&dox->buf, dox->objects.p[i]->is_no_caller_saved_registers); + SerializeStr(&dox->buf, dox->objects.p[i]->visibility); + SerializeJavadown(&dox->buf, dox->objects.p[i]->javadown->javadown); + SerializeInt(&dox->buf, CountParams(dox->objects.p[i]->params)); + for (param = dox->objects.p[i]->params; param; param = param->next) { + s = DescribeType(param->ty); + SerializeStr(&dox->buf, s); + free(s); + SerializeStr(&dox->buf, param->name); + } + } + SerializeInt(&dox->buf, dox->macros.n); + for (i = 0; i < dox->macros.n; ++i) { + SerializeStr(&dox->buf, dox->macros.p[i]->name); + SerializeStr(&dox->buf, dox->macros.p[i]->javadown->file->name); + SerializeInt(&dox->buf, dox->macros.p[i]->javadown->line_no); + SerializeJavadown(&dox->buf, dox->macros.p[i]->javadown->javadown); + } + SerializeInt(&dox->buf, 31337); +} + +static void LoadPublicDefinitions(struct DoxWriter *dox, Obj *prog) { + int i; + Obj *obj; + Macro *macro; + for (obj = prog; obj; obj = obj->next) { + if (obj->is_static) continue; + if (*obj->name == '_') continue; + if (!obj->javadown) continue; + if (obj->is_string_literal) continue; + if (obj->visibility && !strcmp(obj->visibility, "hidden")) continue; + if (strchr(obj->name, '$')) continue; + APPEND(dox->objects); + dox->objects.p[dox->objects.n - 1] = obj; + } + for (i = 0; i < macros.capacity; ++i) { + if (!macros.buckets[i].key) continue; + if (macros.buckets[i].key == (char *)-1) continue; + macro = macros.buckets[i].val; + if (!macro->javadown) continue; + if (!macro->javadown->javadown) continue; + if (*macro->name == '_') continue; + if (strchr(macro->name, '$')) continue; + APPEND(dox->macros); + dox->macros.p[dox->macros.n - 1] = macro; + } +} + +static struct DoxWriter *NewDoxWriter(void) { + return calloc(1, sizeof(struct DoxWriter)); +} + +static void FreeDoxWriter(struct DoxWriter *dox) { + if (dox) { + free(dox->buf.p); + free(dox->macros.p); + free(dox->objects.p); + free(dox); + } +} + +static void WriteDox(struct DoxWriter *dox, const char *path) { + int fd; + CHECK_NE(-1, (fd = creat(path, 0644))); + CHECK_EQ(dox->buf.n, write(fd, dox->buf.p, dox->buf.n)); + close(fd); +} + +/** + * Emits documentation datum for compilation unit just parsed. + */ +void output_javadown(const char *path, Obj *prog) { + struct DoxWriter *dox = NewDoxWriter(); + LoadPublicDefinitions(dox, prog); + SerializeDox(dox, prog); + WriteDox(dox, path); + FreeDoxWriter(dox); +} diff --git a/third_party/chibicc/dox2.c b/third_party/chibicc/dox2.c new file mode 100644 index 000000000..8fa5ba523 --- /dev/null +++ b/third_party/chibicc/dox2.c @@ -0,0 +1,392 @@ +/*-*- 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/alg/alg.h" +#include "libc/bits/bits.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "third_party/chibicc/chibicc.h" + +#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) + +struct Dox { + unsigned char *p; + struct Freelist { + size_t n; + void **p; + } freelist; + struct Set { + size_t n; + struct SetEntry { + unsigned h; + char *s; + } * p; + } names; + struct DoxObjects { + size_t n; + struct DoxObject { + bool ignore; + char *type; + char *name; + char *path; + int line; + bool is_function; + bool is_weak; + bool is_inline; + bool is_noreturn; + bool is_destructor; + bool is_constructor; + bool is_force_align_arg_pointer; + bool is_no_caller_saved_registers; + char *visibility; + struct Javadown *javadown; + struct DoxObjectParams { + size_t n; + struct DoxObjectParam { + char *type; + char *name; + } * p; + } params; + } * p; + } objects; + struct { + size_t n; + int *p; + } objectindex; +}; + +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); +} + +static struct Dox *NewDox(void) { + return calloc(1, sizeof(struct Dox)); +} + +static void FreeDox(struct Dox *dox) { + int i; + if (dox) { + for (i = 0; i < dox->freelist.n; ++i) { + free(dox->freelist.p[i]); + } + free(dox->names.p); + free(dox->freelist.p); + free(dox->objects.p); + free(dox); + } +} + +static void *FreeLater(struct Dox *dox, void *p) { + APPEND(dox->freelist); + dox->freelist.p[dox->freelist.n - 1] = p; + return p; +} + +static int DeserializeInt(struct Dox *dox) { + int x; + x = (unsigned)dox->p[0] << 000 | (unsigned)dox->p[1] << 010 | + (unsigned)dox->p[2] << 020 | (unsigned)dox->p[3] << 030; + dox->p += 4; + return x; +} + +static char *DeserializeStr(struct Dox *dox) { + char *s; + size_t n; + n = DeserializeInt(dox); + s = malloc(n + 1); + memcpy(s, dox->p, n); + s[n] = '\0'; + dox->p += n; + return FreeLater(dox, s); +} + +static struct Javadown *DeserializeJavadown(struct Dox *dox) { + int i; + struct Javadown *jd; + jd = FreeLater(dox, calloc(1, sizeof(struct Javadown))); + jd->isfileoverview = DeserializeInt(dox); + jd->title = DeserializeStr(dox); + jd->text = DeserializeStr(dox); + jd->tags.n = DeserializeInt(dox); + jd->tags.p = FreeLater(dox, malloc(jd->tags.n * sizeof(*jd->tags.p))); + for (i = 0; i < jd->tags.n; ++i) { + jd->tags.p[i].tag = DeserializeStr(dox); + jd->tags.p[i].text = DeserializeStr(dox); + } + return jd; +} + +static void DeserializeObject(struct Dox *dox, struct DoxObject *o) { + int i; + o->ignore = false; + o->type = DeserializeStr(dox); + o->name = DeserializeStr(dox); + o->path = DeserializeStr(dox); + o->line = DeserializeInt(dox); + o->is_function = DeserializeInt(dox); + o->is_weak = DeserializeInt(dox); + o->is_inline = DeserializeInt(dox); + o->is_noreturn = DeserializeInt(dox); + o->is_destructor = DeserializeInt(dox); + o->is_constructor = DeserializeInt(dox); + o->is_force_align_arg_pointer = DeserializeInt(dox); + o->is_no_caller_saved_registers = DeserializeInt(dox); + o->visibility = DeserializeStr(dox); + o->javadown = DeserializeJavadown(dox); + o->params.n = DeserializeInt(dox); + o->params.p = FreeLater(dox, malloc(o->params.n * sizeof(*o->params.p))); + for (i = 0; i < o->params.n; ++i) { + o->params.p[i].type = DeserializeStr(dox); + o->params.p[i].name = DeserializeStr(dox); + } +} + +static void DeserializeDox(struct Dox *dox) { + int i, j, n; + i = dox->objects.n; + n = DeserializeInt(dox); + dox->objects.p = + realloc(dox->objects.p, (dox->objects.n + n) * sizeof(*dox->objects.p)); + for (j = 0; j < n; ++j) { + DeserializeObject(dox, dox->objects.p + i + j); + } + dox->objects.n += n; +} + +static void ReadDox(struct Dox *dox, const StringArray *files) { + int i, fd; + void *map; + struct stat st; + for (i = 0; i < files->len; ++i) { + CHECK_NE(-1, (fd = open(files->data[i], O_RDONLY))); + CHECK_NE(-1, fstat(fd, &st)); + if (st.st_size) { + CHECK_NE(MAP_FAILED, + (map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))); + dox->p = map; + DeserializeDox(dox); + munmap(map, st.st_size); + } + close(fd); + } +} + +static bool AddSet(struct Set *set, char *s) { + unsigned i, h, k; + h = Hash(s, strlen(s)); + k = 0; + for (k = 0;; ++k) { + i = (h + k + ((k + 1) >> 1)) & (set->n - 1); + if (!set->p[i].h) { + set->p[i].h = h; + set->p[i].s = s; + return true; + } + if (h == set->p[i].h && !strcmp(s, set->p[i].s)) { + return false; + } + } +} + +static int CompareObjectNames(const void *a, const void *b, void *arg) { + int *i1, *i2; + struct Dox *dox; + i1 = a, i2 = b, dox = arg; + return strcmp(dox->objects.p[*i1].name, dox->objects.p[*i2].name); +} + +static void IndexDox(struct Dox *dox) { + size_t i, j, n; + dox->names.n = roundup2pow(dox->objects.n) << 1; + dox->names.p = calloc(dox->names.n, sizeof(*dox->names.p)); + for (n = i = 0; i < dox->objects.n; ++i) { + if (AddSet(&dox->names, dox->objects.p[i].name)) { + ++n; + } else { + dox->objects.p[i].ignore = true; + } + } + dox->objectindex.n = n; + dox->objectindex.p = malloc(n * sizeof(*dox->objectindex.p)); + for (j = i = 0; i < dox->objects.n; ++i) { + if (dox->objects.p[i].ignore) continue; + dox->objectindex.p[j++] = i; + } + qsort_r(dox->objectindex.p, dox->objectindex.n, sizeof(*dox->objectindex.p), + CompareObjectNames, dox); +} + +static void PrintText(FILE *f, const char *s) { + int c; + bool bol, pre; + for (pre = false, bol = true;;) { + switch ((c = *s++)) { + case '\0': + if (pre) { + fprintf(f, ""); + } + return; + case '&': + fprintf(f, "&"); + bol = false; + break; + case '<': + fprintf(f, "<"); + bol = false; + break; + case '>': + fprintf(f, ">"); + bol = false; + break; + case '"': + fprintf(f, """); + bol = false; + break; + case '\'': + fprintf(f, "'"); + bol = false; + break; + case '\n': + if (!pre && *s == '\n') { + ++s; + fprintf(f, "\n
"); + } else if (pre && + (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) { + fprintf(f, "\n"); + pre = false; + } else { + fprintf(f, "\n"); + } + bol = true; + break; + case ' ': + if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') { + pre = true; + fprintf(f, "
"); + } + fprintf(f, " "); + bol = false; + break; + default: + fprintf(f, "%c", c); + bol = false; + break; + } + } +} + +static void PrintDox(struct Dox *dox, FILE *f) { + int i, j, k; + char *prefix; + struct DoxObject *o; + fprintf(f, "\ +\n\ +\n\ +\n\ +\n\ +
\n\
+ \n\
+");
+ for (i = 0; i < dox->objectindex.n; ++i) {
+ o = dox->objects.p + dox->objectindex.p[i];
+ if (o->ignore || !o->is_function) continue;
+ fprintf(f, "%s | \n");
+ for (i = 0; i < dox->objectindex.n; ++i) {
+ o = dox->objects.p + dox->objectindex.p[i];
+ if (o->ignore || !o->is_function) continue;
+ fprintf(f, "\n \n", o->name, o->name);
+ fprintf(f, " \n");
+ }
+ fprintf(f, "", o->name); + fprintf(f, "%s", o->name); + fprintf(f, ""); + PrintText(f, o->javadown->title); + fprintf(f, "\n"); + if (*o->javadown->text) { + fprintf(f, " "); + PrintText(f, o->javadown->text); + fprintf(f, "\n"); + } + fprintf(f, " @param\n"); + fprintf(f, " \n");
+ if (o->params.n) {
+ fprintf(f, " \n");
+ for (k = 0; k < o->javadown->tags.n; ++k) {
+ if (!strcmp(o->javadown->tags.p[k].tag, "param")) continue;
+ fprintf(f, "
None.\n"); + } + fprintf(f, " @"); + PrintText(f, o->javadown->tags.p[k].tag); + fprintf(f, "\n"); + if (*o->javadown->tags.p[k].text) { + PrintText(f, o->javadown->tags.p[k].text); + fprintf(f, "\n"); + } + } + fprintf(f, " |