From a98889604846499d78e29188cefccaf3a18f7856 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 20 Jun 2022 03:08:00 -0700 Subject: [PATCH] Add atomics to chibicc This change also fixes #434 and makes the chibicc assembler better. --- libc/intrin/refcount.h | 7 - libc/intrin/wait0.c | 43 +++ libc/intrin/wait0.internal.h | 20 +- libc/linux/futex.h | 10 +- third_party/chibicc/README.cosmo | 2 +- third_party/chibicc/as.c | 13 + third_party/chibicc/asm.c | 22 +- third_party/chibicc/chibicc.h | 12 +- third_party/chibicc/chibicc.mk | 3 +- third_party/chibicc/codegen.c | 98 ++++- third_party/chibicc/help.txt | 12 +- third_party/chibicc/kw.gperf | 11 +- third_party/chibicc/kw.h | 99 ++--- third_party/chibicc/kw.inc | 513 +++++++++++++------------ third_party/chibicc/parse.c | 141 ++++--- third_party/chibicc/test/asm_test.c | 21 + third_party/chibicc/test/atomic_test.c | 41 ++ third_party/chibicc/type.c | 11 +- tool/build/lib/elfwriter.c | 5 +- tool/build/lib/elfwriter.h | 1 - tool/net/redbean.c | 10 +- 21 files changed, 650 insertions(+), 445 deletions(-) delete mode 100644 libc/intrin/refcount.h create mode 100644 libc/intrin/wait0.c create mode 100644 third_party/chibicc/test/atomic_test.c diff --git a/libc/intrin/refcount.h b/libc/intrin/refcount.h deleted file mode 100644 index 076de6a03..000000000 --- a/libc/intrin/refcount.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_ -#define COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_ - -#define _incref(x) __atomic_fetch_add(x, 1, __ATOMIC_RELAXED) -#define _decref(x) __atomic_sub_fetch(x, 1, __ATOMIC_SEQ_CST) - -#endif /* COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_ */ diff --git a/libc/intrin/wait0.c b/libc/intrin/wait0.c new file mode 100644 index 000000000..19883467a --- /dev/null +++ b/libc/intrin/wait0.c @@ -0,0 +1,43 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/intrin/wait0.internal.h" +#include "libc/linux/futex.h" + +/** + * Blocks until memory location becomes zero. + * + * This is intended to be used on the child thread id, which is updated + * by the clone() system call when a thread terminates. The purpose of + * this operation is to know when it's safe to munmap() a thread stack. + */ +void _wait0(int *ptid) { + int x; + for (;;) { + if (!(x = atomic_load_explicit(ptid, memory_order_relaxed))) { + break; + } else if (IsLinux()) { + LinuxFutexWait(ptid, x, 0); + } else { + sched_yield(); + } + } +} diff --git a/libc/intrin/wait0.internal.h b/libc/intrin/wait0.internal.h index 28d104629..d47cd3e82 100644 --- a/libc/intrin/wait0.internal.h +++ b/libc/intrin/wait0.internal.h @@ -1,20 +1,10 @@ #ifndef COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ #define COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ -#include "libc/bits/atomic.h" -#include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/linux/futex.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ -#define _wait0(ptid) \ - do { \ - int x; \ - if (!(x = atomic_load_explicit(ptid, memory_order_relaxed))) { \ - break; \ - } else if (IsLinux()) { \ - LinuxFutexWait(ptid, x, 0); \ - } else { \ - sched_yield(); \ - } \ - } while (1) +void _wait0(int *) hidden; +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ */ diff --git a/libc/linux/futex.h b/libc/linux/futex.h index d778a7a1c..7fc1182bd 100644 --- a/libc/linux/futex.h +++ b/libc/linux/futex.h @@ -1,16 +1,16 @@ #ifndef COSMOPOLITAN_LIBC_LINUX_FUTEX_H_ #define COSMOPOLITAN_LIBC_LINUX_FUTEX_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) #include "libc/calls/struct/timespec.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) forceinline int LinuxFutexWait(void *addr, int expect, struct timespec *timeout) { int ax; - register void *r10 asm("r10") = timeout; - asm volatile("syscall" + asm volatile("mov\t%5,%%r10\n\t" + "syscall" : "=a"(ax) - : "0"(202), "D"(addr), "S"(0), "d"(expect), "r"(r10) - : "rcx", "r11", "memory"); + : "0"(202), "D"(addr), "S"(0), "d"(expect), "g"(timeout) + : "rcx", "r10", "r11", "memory"); return ax; } diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo index 18bbd30fa..7c8d7c738 100644 --- a/third_party/chibicc/README.cosmo +++ b/third_party/chibicc/README.cosmo @@ -13,11 +13,11 @@ local enhancements - support _Static_assert - support __vector_size__ - support __builtin_add_overflow, etc. +- support GCC C11 __atomic_* primitives - support __builtin_memcpy, strlen, strpbrk, etc. - support __builtin_constant_p, __builtin_likely, etc. - support __builtin_isunordered, __builtin_islessgreater, etc. - support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc. -- support __atomic_load, __sync_lock_test_and_set, __sync_lock_release, 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 diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index dbc9bc6be..079ba23d3 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -2356,6 +2356,14 @@ static void OnTest(struct As *a, struct Slice s) { } } +static void OnCmpxchg(struct As *a, struct Slice s) { + int reg, modrm, disp; + reg = GetRegisterReg(a); + ConsumeComma(a); + modrm = ParseModrm(a, &disp); + EmitRexOpModrm(a, 0x0FB0, reg, modrm, disp, 1); +} + static void OnImul(struct As *a, struct Slice s) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { @@ -3074,6 +3082,7 @@ static void OnSeto(struct As *a, struct Slice s) { OpSetcc(a, 0); } static void OnSetp(struct As *a, struct Slice s) { OpSetcc(a, 10); } static void OnSets(struct As *a, struct Slice s) { OpSetcc(a, 8); } static void OnSetz(struct As *a, struct Slice s) { OpSetcc(a, 4); } +static void OnSfence(struct As *a, struct Slice s) { EmitVarword(a, 0x0faef8); } static void OnShl(struct As *a, struct Slice s) { OpBsu(a, s, 4); } static void OnShr(struct As *a, struct Slice s) { OpBsu(a, s, 5); } static void OnShufpd(struct As *a, struct Slice s) { OpSseIb(a, 0x660FC6); } @@ -3094,6 +3103,7 @@ static void OnSubpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5C); } static void OnSubps(struct As *a, struct Slice s) { OpSse(a, 0x0F5C); } static void OnSubsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5C); } static void OnSubss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5C); } +static void OnSyscall(struct As *a, struct Slice s) { EmitVarword(a, 0x0F05); } static void OnUcomisd(struct As *a, struct Slice s) { OpSse(a, 0x660F2E); } static void OnUcomiss(struct As *a, struct Slice s) { OpSse(a, 0x0F2E); } static void OnUd2(struct As *a, struct Slice s) { EmitVarword(a, 0x0F0B); } @@ -3229,6 +3239,7 @@ static const struct Directive8 { {"cmpsd", OnCmpsd}, // {"cmpss", OnCmpss}, // {"cmpw", OnCmp}, // + {"cmpxchg", OnCmpxchg}, // {"comisd", OnComisd}, // {"comiss", OnComiss}, // {"cqo", OnCqto}, // @@ -3604,6 +3615,7 @@ static const struct Directive8 { {"setpo", OnSetnp}, // {"sets", OnSets}, // {"setz", OnSetz}, // + {"sfence", OnSfence}, // {"shl", OnShl}, // {"shlb", OnShl}, // {"shld", OnShld}, // @@ -3638,6 +3650,7 @@ static const struct Directive8 { {"subsd", OnSubsd}, // {"subss", OnSubss}, // {"subw", OnSub}, // + {"syscall", OnSyscall}, // {"test", OnTest}, // {"testb", OnTest}, // {"testl", OnTest}, // diff --git a/third_party/chibicc/asm.c b/third_party/chibicc/asm.c index 120b60fe8..b88d13810 100644 --- a/third_party/chibicc/asm.c +++ b/third_party/chibicc/asm.c @@ -232,7 +232,9 @@ static int PickAsmOperandType(Asm *a, AsmOperand *op) { op->type &= ~kAsmImm; if (!IsLvalue(op)) error_tok(op->tok, "lvalue required"); } - if ((op->type & kAsmImm) && is_const_expr(op->node)) { + if ((op->type & kAsmImm) && (is_const_expr(op->node) || + // TODO(jart): confirm this is what we want + op->node->ty->kind == TY_FUNC)) { op->val = eval2(op->node, &op->label); return kAsmImm; } @@ -277,13 +279,13 @@ static Token *ParseAsmOperands(Asm *a, Token *tok) { return tok; } -static void CouldNotAllocateRegister(AsmOperand *op) { - error_tok(op->tok, "could not allocate register"); +static void CouldNotAllocateRegister(AsmOperand *op, const char *kind) { + error_tok(op->tok, "could not allocate %s register", kind); } static void PickAsmRegisters(Asm *a) { - int i, j, m, regset, xmmset, x87sts; - regset = 0b0000111111000111; // exclude bx,sp,bp,r12-r15 + int i, j, m, pick, regset, xmmset, x87sts; + regset = 0b1111111111000111; // exclude bx,sp,bp xmmset = 0b1111111111111111; x87sts = 0b0000000011111111; regset ^= regset & a->regclob; // don't allocate from clobber list @@ -296,20 +298,22 @@ static void PickAsmRegisters(Asm *a) { case kAsmReg: if (!(m = a->ops[i].regmask)) break; if (popcnt(m) != j) break; - if (!(m &= regset)) CouldNotAllocateRegister(&a->ops[i]); - regset &= ~(1 << (a->ops[i].reg = bsf(m))); + if (!(m &= regset)) CouldNotAllocateRegister(&a->ops[i], "rm"); + pick = 1 << (a->ops[i].reg = bsf(m)); + if (pick & PRECIOUS) a->regclob |= pick; + regset &= ~pick; a->ops[i].regmask = 0; break; case kAsmXmm: if (!(m = a->ops[i].regmask)) break; - if (!(m &= xmmset)) CouldNotAllocateRegister(&a->ops[i]); + if (!(m &= xmmset)) CouldNotAllocateRegister(&a->ops[i], "xmm"); xmmset &= ~(1 << (a->ops[i].reg = bsf(m))); a->ops[i].regmask = 0; break; case kAsmFpu: if (!(m = a->ops[i].x87mask)) break; if (popcnt(m) != j) break; - if (!(m &= x87sts)) CouldNotAllocateRegister(&a->ops[i]); + if (!(m &= x87sts)) CouldNotAllocateRegister(&a->ops[i], "fpu"); x87sts &= ~(1 << (a->ops[i].reg = bsf(m))); a->ops[i].x87mask = 0; break; diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 171f1c8fa..94785b3bd 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -344,14 +344,20 @@ typedef enum { ND_MEMZERO, // Zero-clear a stack variable ND_ASM, // "asm" ND_CAS, // Atomic compare-and-swap - ND_EXCH, // Atomic exchange - ND_LOAD, // Atomic load - ND_STORE, // Atomic store + ND_EXCH_N, // Atomic exchange with value + ND_LOAD, // Atomic load to pointer + ND_LOAD_N, // Atomic load to result + ND_STORE, // Atomic store to pointer + ND_STORE_N, // Atomic store to result ND_TESTANDSET, // Sync lock test and set ND_TESTANDSETA, // Atomic lock test and set ND_CLEAR, // Atomic clear ND_RELEASE, // Atomic lock release ND_FETCHADD, // Atomic fetch and add + ND_FETCHSUB, // Atomic fetch and sub + ND_FETCHXOR, // Atomic fetch and xor + ND_FETCHAND, // Atomic fetch and and + ND_FETCHOR, // Atomic fetch and or ND_SUBFETCH, // Atomic sub and fetch ND_FPCLASSIFY, // floating point classify ND_MOVNTDQ, // Intel MOVNTDQ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index ec8c020db..20326725e 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -15,7 +15,8 @@ CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com CHIBICC_FLAGS = \ -fno-common \ -include libc/integral/normalize.inc \ - -DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) + -DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \ + -DMODE='"$(MODE)"' PKGS += THIRD_PARTY_CHIBICC THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index da74d080e..3f7bd911b 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -262,6 +262,20 @@ static char *reg_ax(int sz) { UNREACHABLE(); } +static char *reg_r8(int sz) { + switch (sz) { + case 1: + return "%r8b"; + case 2: + return "%r8w"; + case 4: + return "%r8d"; + case 8: + return "%r8"; + } + UNREACHABLE(); +} + static char *reg_di(int sz) { switch (sz) { case 1: @@ -276,6 +290,20 @@ static char *reg_di(int sz) { UNREACHABLE(); } +static char *reg_si(int sz) { + switch (sz) { + case 1: + return "%sil"; + case 2: + return "%si"; + case 4: + return "%esi"; + case 8: + return "%rsi"; + } + UNREACHABLE(); +} + static const char *gotpcrel(void) { if (opt_pic) { return "@gotpcrel(%rip)"; @@ -1136,6 +1164,21 @@ static void HandleOverflow(const char *ax) { emitlin("\tmovzbl\t%al,%eax"); } +static void HandleAtomicArithmetic(Node *node, const char *op) { + gen_expr(node->lhs); + push(); + gen_expr(node->rhs); + pop("%r9"); + println("\tmov\t%s,%s", reg_ax(node->ty->size), reg_si(node->ty->size)); + println("\tmov\t(%%r9),%s", reg_ax(node->ty->size)); + println("1:\tmov\t%s,%s", reg_ax(node->ty->size), reg_dx(node->ty->size)); + println("\tmov\t%s,%s", reg_ax(node->ty->size), reg_di(node->ty->size)); + println("\t%s\t%s,%s", op, reg_si(node->ty->size), reg_dx(node->ty->size)); + println("\tlock cmpxchg\t%s,(%%r9)", reg_dx(node->ty->size)); + println("\tjnz\t1b"); + println("\tmov\t%s,%s", reg_di(node->ty->size), reg_ax(node->ty->size)); +} + // Generate code for a given node. void gen_expr(Node *node) { char fbuf[32]; @@ -1520,7 +1563,7 @@ void gen_expr(Node *node) { println("\tmov\t$%s,%%eax", node->unique_label); } return; - case ND_CAS: { + case ND_CAS: gen_expr(node->cas_addr); push(); gen_expr(node->cas_new); @@ -1531,14 +1574,11 @@ void gen_expr(Node *node) { pop("%rdx"); // new pop("%rdi"); // addr println("\tlock cmpxchg %s,(%%rdi)", reg_dx(node->ty->size)); - emitlin("\tsete\t%cl"); - emitlin("\tje\t1f"); println("\tmov\t%s,(%%r8)", reg_ax(node->ty->size)); - emitlin("1:"); - emitlin("\tmovzbl\t%cl,%eax"); + emitlin("\tsetz\t%al"); + emitlin("\tmovzbl\t%al,%eax"); return; - } - case ND_EXCH: + case ND_EXCH_N: case ND_TESTANDSET: { gen_expr(node->lhs); push(); @@ -1564,6 +1604,11 @@ void gen_expr(Node *node) { println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); return; } + case ND_LOAD_N: { + gen_expr(node->lhs); + println("\tmov\t(%%rax),%s", reg_ax(node->ty->size)); + return; + } case ND_STORE: { gen_expr(node->lhs); push(); @@ -1576,7 +1621,17 @@ void gen_expr(Node *node) { } return; } - case ND_CLEAR: { + case ND_STORE_N: + gen_expr(node->lhs); + push(); + gen_expr(node->rhs); + pop("%rdi"); + println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); + if (node->memorder) { + println("\tmfence"); + } + return; + case ND_CLEAR: gen_expr(node->lhs); println("\tmov\t%%rax,%%rdi"); println("\txor\t%%eax,%%eax"); @@ -1585,16 +1640,31 @@ void gen_expr(Node *node) { println("\tmfence"); } return; - } - case ND_FETCHADD: { + case ND_FETCHADD: gen_expr(node->lhs); push(); gen_expr(node->rhs); pop("%rdi"); println("\txadd\t%s,(%%rdi)", reg_ax(node->ty->size)); return; - } - case ND_SUBFETCH: { + case ND_FETCHSUB: + gen_expr(node->lhs); + push(); + gen_expr(node->rhs); + pop("%rdi"); + println("\tneg\t%s", reg_ax(node->ty->size)); + println("\txadd\t%s,(%%rdi)", reg_ax(node->ty->size)); + return; + case ND_FETCHXOR: + HandleAtomicArithmetic(node, "xor"); + return; + case ND_FETCHAND: + HandleAtomicArithmetic(node, "and"); + return; + case ND_FETCHOR: + HandleAtomicArithmetic(node, "or"); + return; + case ND_SUBFETCH: gen_expr(node->lhs); push(); gen_expr(node->rhs); @@ -1605,15 +1675,13 @@ void gen_expr(Node *node) { pop("%rdi"); println("\tsub\t%s,%s", reg_di(node->ty->size), reg_ax(node->ty->size)); return; - } - case ND_RELEASE: { + case ND_RELEASE: gen_expr(node->lhs); push(); pop("%rdi"); println("\txor\t%%eax,%%eax"); println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); return; - } case ND_FPCLASSIFY: gen_fpclassify(node->fpc); return; diff --git a/third_party/chibicc/help.txt b/third_party/chibicc/help.txt index 1e2730726..54c585310 100644 --- a/third_party/chibicc/help.txt +++ b/third_party/chibicc/help.txt @@ -196,7 +196,6 @@ BUILTIN FUNCTIONS int __builtin_unreachable() void * __builtin_frame_address(int) _Bool __builtin_types_compatible_p(typename, typename) - T __builtin_compare_and_swap(T *addr, T old, T neu) T __builtin_atomic_exchange(T *addr, T neu) T * __builtin_assume_aligned(T *addr) _Bool __builtin_add_overflow(T, T, T *) @@ -261,11 +260,18 @@ BUILTIN FUNCTIONS long double __builtin_copysignl(long double, long double) void __builtin_ia32_movntq(di *, di) int __builtin_ia32_pmovmskb128(v16qi) - T __atomic_load(T *addr, int memorder) + T __atomic_load_n(T *addr, int memorder) + void __atomic_load(T *addr, T *res, int memorder) + void __atomic_store_n(T *addr, T val, int memorder) + void __atomic_store(T *addr, T *val, int memorder) void __atomic_clear(_Bool *addr, int memorder) _Bool __atomic_test_and_set(void *addr, int memorder) - T __atomic_sub_fetch(T *addr, T amt, int memorder) T __atomic_fetch_add(T *addr, T amt, int memorder) + T __atomic_fetch_sub(T *addr, T amt, int memorder) + T __atomic_fetch_xor(T *addr, T amt, int memorder) + T __atomic_fetch_and(T *addr, T amt, int memorder) + T __atomic_fetch_or(T *addr, T amt, int memorder) + _Bool __atomic_compare_exchange_n(T *addr, T *old, T neu, int weak, int goodorder, int failorder) T __sync_lock_test_and_set(T *addr, T value, ...) void __sync_lock_release(T *addr, ...) diff --git a/third_party/chibicc/kw.gperf b/third_party/chibicc/kw.gperf index 220da7e6e..2bb630046 100644 --- a/third_party/chibicc/kw.gperf +++ b/third_party/chibicc/kw.gperf @@ -81,8 +81,6 @@ __thread, KW__THREAD_LOCAL __typeof, KW_TYPEOF __builtin_add_overflow, KW___BUILTIN_ADD_OVERFLOW __builtin_assume_aligned, KW___BUILTIN_ASSUME_ALIGNED -__atomic_exchange, KW___ATOMIC_EXCHANGE -__builtin_compare_and_swap, KW___BUILTIN_COMPARE_AND_SWAP __builtin_constant_p, KW___BUILTIN_CONSTANT_P __builtin_expect, KW___BUILTIN_EXPECT __builtin_ffs, KW___BUILTIN_FFS @@ -119,12 +117,19 @@ __builtin_types_compatible_p, KW___BUILTIN_TYPES_COMPATIBLE_P "->", KW_ARROW ".", KW_DOT __atomic_load, KW___ATOMIC_LOAD +__atomic_load_n, KW___ATOMIC_LOAD_N __atomic_store, KW___ATOMIC_STORE +__atomic_store_n, KW___ATOMIC_STORE_N __atomic_clear, KW___ATOMIC_CLEAR -__atomic_sub_fetch, KW___ATOMIC_SUB_FETCH __atomic_fetch_add, KW___ATOMIC_FETCH_ADD +__atomic_fetch_sub, KW___ATOMIC_FETCH_SUB +__atomic_fetch_and, KW___ATOMIC_FETCH_AND +__atomic_fetch_xor, KW___ATOMIC_FETCH_XOR +__atomic_fetch_or, KW___ATOMIC_FETCH_OR __atomic_test_and_set, KW___ATOMIC_TEST_AND_SET __sync_lock_test_and_set, KW___SYNC_LOCK_TEST_AND_SET __sync_lock_release, KW___SYNC_LOCK_RELEASE __builtin_ia32_movntdq, KW___BUILTIN_IA32_MOVNTDQ __builtin_ia32_pmovmskb128, KW___BUILTIN_IA32_PMOVMSKB128 +__atomic_compare_exchange_n, KW___ATOMIC_COMPARE_EXCHANGE_N +__atomic_exchange_n, KW___ATOMIC_EXCHANGE_N diff --git a/third_party/chibicc/kw.h b/third_party/chibicc/kw.h index 79aa5f796..d8b7baa0c 100644 --- a/third_party/chibicc/kw.h +++ b/third_party/chibicc/kw.h @@ -68,53 +68,58 @@ #define KW___ASM__ 84 #define KW___BUILTIN_ADD_OVERFLOW 85 #define KW___BUILTIN_ASSUME_ALIGNED 86 -#define KW___ATOMIC_EXCHANGE 87 -#define KW___BUILTIN_COMPARE_AND_SWAP 88 -#define KW___BUILTIN_CONSTANT_P 89 -#define KW___BUILTIN_EXPECT 90 -#define KW___BUILTIN_FFS 91 -#define KW___BUILTIN_FFSL 92 -#define KW___BUILTIN_FFSLL 93 -#define KW___BUILTIN_FPCLASSIFY 94 -#define KW___BUILTIN_MUL_OVERFLOW 95 -#define KW___BUILTIN_NEG_OVERFLOW 96 -#define KW___BUILTIN_OFFSETOF 97 -#define KW___BUILTIN_POPCOUNT 98 -#define KW___BUILTIN_POPCOUNTL 99 -#define KW___BUILTIN_POPCOUNTLL 100 -#define KW___BUILTIN_REG_CLASS 101 -#define KW___BUILTIN_STRCHR 102 -#define KW___BUILTIN_STRLEN 103 -#define KW___BUILTIN_STRPBRK 104 -#define KW___BUILTIN_STRSTR 105 -#define KW___BUILTIN_SUB_OVERFLOW 106 -#define KW___BUILTIN_TYPES_COMPATIBLE_P 107 -#define KW_LP 108 -#define KW_RP 109 -#define KW_LB 110 -#define KW_RB 111 -#define KW_PLUS 112 -#define KW_MINUS 113 -#define KW_AMP 114 -#define KW_STAR 115 -#define KW_EXCLAIM 116 -#define KW_TILDE 117 -#define KW_INCREMENT 118 -#define KW_DECREMENT 119 -#define KW_LOGAND 120 -#define KW_LOGOR 121 -#define KW_ARROW 122 -#define KW_DOT 123 -#define KW___ATOMIC_LOAD 124 -#define KW___SYNC_LOCK_TEST_AND_SET 125 -#define KW___SYNC_LOCK_RELEASE 126 -#define KW___BUILTIN_IA32_PMOVMSKB128 127 -#define KW___BUILTIN_IA32_MOVNTDQ 128 -#define KW___ATOMIC_FETCH_ADD 129 -#define KW___ATOMIC_SUB_FETCH 130 -#define KW___ATOMIC_TEST_AND_SET 131 -#define KW___ATOMIC_CLEAR 132 -#define KW___ATOMIC_STORE 133 +#define KW___BUILTIN_CONSTANT_P 87 +#define KW___BUILTIN_EXPECT 88 +#define KW___BUILTIN_FFS 89 +#define KW___BUILTIN_FFSL 90 +#define KW___BUILTIN_FFSLL 91 +#define KW___BUILTIN_FPCLASSIFY 92 +#define KW___BUILTIN_MUL_OVERFLOW 93 +#define KW___BUILTIN_NEG_OVERFLOW 94 +#define KW___BUILTIN_OFFSETOF 95 +#define KW___BUILTIN_POPCOUNT 96 +#define KW___BUILTIN_POPCOUNTL 97 +#define KW___BUILTIN_POPCOUNTLL 98 +#define KW___BUILTIN_REG_CLASS 99 +#define KW___BUILTIN_STRCHR 100 +#define KW___BUILTIN_STRLEN 101 +#define KW___BUILTIN_STRPBRK 102 +#define KW___BUILTIN_STRSTR 103 +#define KW___BUILTIN_SUB_OVERFLOW 104 +#define KW___BUILTIN_TYPES_COMPATIBLE_P 105 +#define KW_LP 106 +#define KW_RP 107 +#define KW_LB 108 +#define KW_RB 109 +#define KW_PLUS 110 +#define KW_MINUS 111 +#define KW_AMP 112 +#define KW_STAR 113 +#define KW_EXCLAIM 114 +#define KW_TILDE 115 +#define KW_INCREMENT 116 +#define KW_DECREMENT 117 +#define KW_LOGAND 118 +#define KW_LOGOR 119 +#define KW_ARROW 120 +#define KW_DOT 121 +#define KW___ATOMIC_LOAD 122 +#define KW___SYNC_LOCK_TEST_AND_SET 123 +#define KW___SYNC_LOCK_RELEASE 124 +#define KW___BUILTIN_IA32_PMOVMSKB128 125 +#define KW___BUILTIN_IA32_MOVNTDQ 126 +#define KW___ATOMIC_FETCH_ADD 127 +#define KW___ATOMIC_TEST_AND_SET 128 +#define KW___ATOMIC_CLEAR 129 +#define KW___ATOMIC_STORE 130 +#define KW___ATOMIC_STORE_N 131 +#define KW___ATOMIC_LOAD_N 132 +#define KW___ATOMIC_FETCH_SUB 133 +#define KW___ATOMIC_FETCH_AND 134 +#define KW___ATOMIC_FETCH_OR 135 +#define KW___ATOMIC_FETCH_XOR 136 +#define KW___ATOMIC_COMPARE_EXCHANGE_N 137 +#define KW___ATOMIC_EXCHANGE_N 138 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/third_party/chibicc/kw.inc b/third_party/chibicc/kw.inc index 9238b0dba..d58edb937 100644 --- a/third_party/chibicc/kw.inc +++ b/third_party/chibicc/kw.inc @@ -1,6 +1,6 @@ /* ANSI-C code produced by gperf version 3.1 */ /* Command-line: gperf kw.gperf */ -/* Computed positions: -k'1,4,11,14,$' */ +/* Computed positions: -k'1,4,11,14,17,$' */ // clang-format off #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -37,50 +37,55 @@ #line 10 "kw.gperf" struct thatispacked KwSlot { char *name; unsigned char code; }; -#define TOTAL_KEYWORDS 119 +#define TOTAL_KEYWORDS 124 #define MIN_WORD_LENGTH 1 #define MAX_WORD_LENGTH 28 #define MIN_HASH_VALUE 1 -#define MAX_HASH_VALUE 238 -/* maximum key range = 238, duplicates = 0 */ +#define MAX_HASH_VALUE 256 +/* maximum key range = 256, duplicates = 0 */ static inline unsigned int hash (register const char *str, register size_t len) { - static const unsigned char asso_values[] = + static const unsigned short asso_values[] = { - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 115, 239, 239, 239, 239, 50, 239, - 110, 105, 100, 5, 239, 0, 95, 239, 239, 239, - 10, 239, 239, 239, 239, 239, 0, 239, 239, 239, - 239, 239, 45, 239, 239, 239, 0, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 5, 239, 0, 90, 5, - 55, 10, 0, 25, 75, 105, 15, 10, 20, 15, - 125, 60, 15, 10, 10, 10, 0, 70, 5, 5, - 10, 0, 45, 85, 10, 30, 15, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 239 + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 100, 257, 257, 257, 257, 25, 257, + 95, 90, 85, 5, 257, 0, 80, 257, 257, 257, + 0, 257, 257, 257, 257, 257, 10, 257, 257, 257, + 257, 257, 35, 257, 257, 257, 0, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 5, 257, 15, 120, 5, + 25, 0, 0, 45, 85, 115, 65, 0, 25, 90, + 40, 50, 5, 15, 25, 10, 0, 0, 10, 5, + 20, 5, 90, 75, 20, 70, 65, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257 }; register unsigned int hval = len; switch (hval) { default: + hval += asso_values[(unsigned char)str[16]]; + /*FALLTHROUGH*/ + case 16: + case 15: + case 14: hval += asso_values[(unsigned char)str[13]]; /*FALLTHROUGH*/ case 13: @@ -112,24 +117,30 @@ LookupKw (register const char *str, register size_t len) static const struct thatispacked KwSlot wordlist[] = { {""}, -#line 110 "kw.gperf" +#line 108 "kw.gperf" {"-", KW_MINUS}, -#line 116 "kw.gperf" +#line 114 "kw.gperf" {"--", KW_DECREMENT}, - {""}, {""}, {""}, + {""}, +#line 19 "kw.gperf" + {"else", KW_ELSE}, +#line 64 "kw.gperf" + {"undef", KW_UNDEF}, #line 63 "kw.gperf" {"typeof", KW_TYPEOF}, #line 62 "kw.gperf" {"typedef", KW_TYPEDEF}, - {""}, {""}, + {""}, +#line 15 "kw.gperf" + {"case", KW_CASE}, #line 29 "kw.gperf" {"const", KW_CONST}, -#line 109 "kw.gperf" +#line 107 "kw.gperf" {"+", KW_PLUS}, -#line 115 "kw.gperf" +#line 113 "kw.gperf" {"++", KW_INCREMENT}, -#line 20 "kw.gperf" - {"for", KW_FOR}, +#line 35 "kw.gperf" + {"continue", KW_CONTINUE}, {""}, #line 78 "kw.gperf" {"__restrict", KW_RESTRICT}, @@ -137,269 +148,275 @@ LookupKw (register const char *str, register size_t len) {"sizeof", KW_SIZEOF}, #line 75 "kw.gperf" {"__asm__", KW___ASM__}, -#line 41 "kw.gperf" - {"asm", KW_ASM}, -#line 15 "kw.gperf" - {"case", KW_CASE}, + {""}, +#line 121 "kw.gperf" + {"__atomic_store", KW___ATOMIC_STORE}, #line 73 "kw.gperf" {"__VA_OPT__", KW___VA_OPT__}, -#line 13 "kw.gperf" - {"struct", KW_STRUCT}, -#line 118 "kw.gperf" - {"||", KW_LOGOR}, - {""}, -#line 19 "kw.gperf" - {"else", KW_ELSE}, -#line 31 "kw.gperf" - {"short", KW_SHORT}, -#line 61 "kw.gperf" - {"strstr", KW_STRSTR}, -#line 79 "kw.gperf" - {"__restrict__", KW_RESTRICT}, -#line 67 "kw.gperf" - {"_Alignof", KW__ALIGNOF}, -#line 18 "kw.gperf" - {"char", KW_CHAR}, -#line 48 "kw.gperf" - {"endif", KW_ENDIF}, -#line 114 "kw.gperf" - {"~", KW_TILDE}, +#line 16 "kw.gperf" + {"static", KW_STATIC}, #line 68 "kw.gperf" {"_Atomic", KW__ATOMIC}, -#line 88 "kw.gperf" - {"__builtin_ffs", KW___BUILTIN_FFS}, +#line 45 "kw.gperf" + {"__attribute__", KW___ATTRIBUTE__}, + {""}, +#line 31 "kw.gperf" + {"short", KW_SHORT}, +#line 13 "kw.gperf" + {"struct", KW_STRUCT}, +#line 79 "kw.gperf" + {"__restrict__", KW_RESTRICT}, +#line 20 "kw.gperf" + {"for", KW_FOR}, #line 55 "kw.gperf" {"line", KW_LINE}, -#line 25 "kw.gperf" - {"while", KW_WHILE}, {""}, +#line 85 "kw.gperf" + {"__builtin_expect", KW___BUILTIN_EXPECT}, #line 60 "kw.gperf" {"strpbrk", KW_STRPBRK}, -#line 66 "kw.gperf" - {"_Alignas", KW__ALIGNAS}, -#line 47 "kw.gperf" - {"elif", KW_ELIF}, +#line 57 "kw.gperf" + {"restrict", KW_RESTRICT}, + {""}, #line 49 "kw.gperf" {"error", KW_ERROR}, -#line 74 "kw.gperf" - {"__alignof__", KW___ALIGNOF__}, -#line 82 "kw.gperf" - {"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW}, -#line 44 "kw.gperf" - {"register", KW_REGISTER}, - {""}, +#line 28 "kw.gperf" + {"double", KW_DOUBLE}, +#line 117 "kw.gperf" + {"->", KW_ARROW}, +#line 86 "kw.gperf" + {"__builtin_ffs", KW___BUILTIN_FFS}, +#line 17 "kw.gperf" + {"void", KW_VOID}, #line 69 "kw.gperf" {"_Bool", KW__BOOL}, -#line 87 "kw.gperf" - {"__builtin_expect", KW___BUILTIN_EXPECT}, -#line 119 "kw.gperf" - {"->", KW_ARROW}, -#line 95 "kw.gperf" - {"__builtin_popcount", KW___BUILTIN_POPCOUNT}, +#line 61 "kw.gperf" + {"strstr", KW_STRSTR}, +#line 116 "kw.gperf" + {"||", KW_LOGOR}, {""}, -#line 91 "kw.gperf" - {"__builtin_fpclassify", KW___BUILTIN_FPCLASSIFY}, +#line 18 "kw.gperf" + {"char", KW_CHAR}, + {""}, +#line 50 "kw.gperf" + {"extern", KW_EXTERN}, #line 99 "kw.gperf" - {"__builtin_strchr", KW___BUILTIN_STRCHR}, -#line 103 "kw.gperf" + {"__builtin_strpbrk", KW___BUILTIN_STRPBRK}, + {""}, +#line 47 "kw.gperf" + {"elif", KW_ELIF}, +#line 26 "kw.gperf" + {"union", KW_UNION}, +#line 109 "kw.gperf" + {"&", KW_AMP}, +#line 115 "kw.gperf" + {"&&", KW_LOGAND}, +#line 102 "kw.gperf" + {"__builtin_types_compatible_p", KW___BUILTIN_TYPES_COMPATIBLE_P}, + {""}, {""}, +#line 129 "kw.gperf" + {"__atomic_test_and_set", KW___ATOMIC_TEST_AND_SET}, +#line 101 "kw.gperf" {"__builtin_sub_overflow", KW___BUILTIN_SUB_OVERFLOW}, #line 72 "kw.gperf" {"_Thread_local", KW__THREAD_LOCAL}, -#line 98 "kw.gperf" - {"__builtin_reg_class", KW___BUILTIN_REG_CLASS}, - {""}, -#line 102 "kw.gperf" - {"__builtin_strstr", KW___BUILTIN_STRSTR}, -#line 92 "kw.gperf" - {"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW}, -#line 81 "kw.gperf" - {"__typeof", KW_TYPEOF}, - {""}, -#line 86 "kw.gperf" - {"__builtin_constant_p", KW___BUILTIN_CONSTANT_P}, -#line 108 "kw.gperf" - {"}", KW_RB}, -#line 101 "kw.gperf" - {"__builtin_strpbrk", KW___BUILTIN_STRPBRK}, -#line 104 "kw.gperf" - {"__builtin_types_compatible_p", KW___BUILTIN_TYPES_COMPATIBLE_P}, -#line 89 "kw.gperf" - {"__builtin_ffsl", KW___BUILTIN_FFSL}, -#line 90 "kw.gperf" - {"__builtin_ffsll", KW___BUILTIN_FFSLL}, - {""}, {""}, {""}, -#line 96 "kw.gperf" - {"__builtin_popcountl", KW___BUILTIN_POPCOUNTL}, -#line 97 "kw.gperf" - {"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL}, -#line 85 "kw.gperf" - {"__builtin_compare_and_swap", KW___BUILTIN_COMPARE_AND_SWAP}, - {""}, -#line 77 "kw.gperf" - {"__int128", KW___INT128}, -#line 17 "kw.gperf" - {"void", KW_VOID}, -#line 64 "kw.gperf" - {"undef", KW_UNDEF}, -#line 28 "kw.gperf" - {"double", KW_DOUBLE}, - {""}, -#line 70 "kw.gperf" - {"_Generic", KW__GENERIC}, -#line 43 "kw.gperf" - {"auto", KW_AUTO}, + {""}, {""}, +#line 122 "kw.gperf" + {"__atomic_store_n", KW___ATOMIC_STORE_N}, +#line 82 "kw.gperf" + {"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW}, +#line 76 "kw.gperf" + {"__inline", KW_INLINE}, +#line 46 "kw.gperf" + {"_Noreturn", KW__NORETURN}, {""}, #line 58 "kw.gperf" {"strchr", KW_STRCHR}, {""}, -#line 76 "kw.gperf" - {"__inline", KW_INLINE}, +#line 70 "kw.gperf" + {"_Generic", KW__GENERIC}, + {""}, +#line 48 "kw.gperf" + {"endif", KW_ENDIF}, +#line 97 "kw.gperf" + {"__builtin_strchr", KW___BUILTIN_STRCHR}, + {""}, +#line 77 "kw.gperf" + {"__int128", KW___INT128}, +#line 43 "kw.gperf" + {"auto", KW_AUTO}, +#line 89 "kw.gperf" + {"__builtin_fpclassify", KW___BUILTIN_FPCLASSIFY}, +#line 100 "kw.gperf" + {"__builtin_strstr", KW___BUILTIN_STRSTR}, +#line 21 "kw.gperf" + {"do", KW_DO}, +#line 67 "kw.gperf" + {"_Alignof", KW__ALIGNOF}, +#line 87 "kw.gperf" + {"__builtin_ffsl", KW___BUILTIN_FFSL}, +#line 88 "kw.gperf" + {"__builtin_ffsll", KW___BUILTIN_FFSLL}, +#line 14 "kw.gperf" + {"return", KW_RETURN}, + {""}, +#line 93 "kw.gperf" + {"__builtin_popcount", KW___BUILTIN_POPCOUNT}, +#line 83 "kw.gperf" + {"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED}, {""}, {""}, +#line 91 "kw.gperf" + {"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW}, +#line 66 "kw.gperf" + {"_Alignas", KW__ALIGNAS}, +#line 96 "kw.gperf" + {"__builtin_reg_class", KW___BUILTIN_REG_CLASS}, + {""}, +#line 32 "kw.gperf" + {"signed", KW_SIGNED}, + {""}, +#line 119 "kw.gperf" + {"__atomic_load", KW___ATOMIC_LOAD}, +#line 123 "kw.gperf" + {"__atomic_clear", KW___ATOMIC_CLEAR}, +#line 84 "kw.gperf" + {"__builtin_constant_p", KW___BUILTIN_CONSTANT_P}, #line 39 "kw.gperf" {"define", KW_DEFINE}, {""}, -#line 57 "kw.gperf" - {"restrict", KW_RESTRICT}, - {""}, {""}, -#line 16 "kw.gperf" - {"static", KW_STATIC}, +#line 23 "kw.gperf" + {"unsigned", KW_UNSIGNED}, +#line 135 "kw.gperf" + {"__atomic_exchange_n", KW___ATOMIC_EXCHANGE_N}, +#line 25 "kw.gperf" + {"while", KW_WHILE}, +#line 27 "kw.gperf" + {"switch", KW_SWITCH}, {""}, -#line 35 "kw.gperf" - {"continue", KW_CONTINUE}, -#line 127 "kw.gperf" - {"__sync_lock_test_and_set", KW___SYNC_LOCK_TEST_AND_SET}, -#line 30 "kw.gperf" - {"float", KW_FLOAT}, -#line 56 "kw.gperf" - {"pragma", KW_PRAGMA}, - {""}, -#line 94 "kw.gperf" - {"__builtin_offsetof", KW___BUILTIN_OFFSETOF}, -#line 128 "kw.gperf" - {"__sync_lock_release", KW___SYNC_LOCK_RELEASE}, - {""}, -#line 111 "kw.gperf" - {"&", KW_AMP}, -#line 117 "kw.gperf" - {"&&", KW_LOGAND}, -#line 45 "kw.gperf" - {"__attribute__", KW___ATTRIBUTE__}, +#line 81 "kw.gperf" + {"__typeof", KW_TYPEOF}, #line 51 "kw.gperf" {"goto", KW_GOTO}, - {""}, {""}, + {""}, +#line 98 "kw.gperf" + {"__builtin_strlen", KW___BUILTIN_STRLEN}, + {""}, +#line 41 "kw.gperf" + {"asm", KW_ASM}, +#line 94 "kw.gperf" + {"__builtin_popcountl", KW___BUILTIN_POPCOUNTL}, +#line 95 "kw.gperf" + {"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL}, +#line 56 "kw.gperf" + {"pragma", KW_PRAGMA}, + {""}, {""}, {""}, +#line 120 "kw.gperf" + {"__atomic_load_n", KW___ATOMIC_LOAD_N}, +#line 74 "kw.gperf" + {"__alignof__", KW___ALIGNOF__}, #line 12 "kw.gperf" {"if", KW_IF}, #line 54 "kw.gperf" {"int", KW_INT}, -#line 122 "kw.gperf" - {"__atomic_store", KW___ATOMIC_STORE}, + {""}, #line 37 "kw.gperf" {"ifdef", KW_IFDEF}, -#line 126 "kw.gperf" - {"__atomic_test_and_set", KW___ATOMIC_TEST_AND_SET}, -#line 84 "kw.gperf" - {"__atomic_exchange", KW___ATOMIC_EXCHANGE}, +#line 38 "kw.gperf" + {"ifndef", KW_IFNDEF}, +#line 40 "kw.gperf" + {"defined", KW_DEFINED}, +#line 44 "kw.gperf" + {"register", KW_REGISTER}, +#line 130 "kw.gperf" + {"__sync_lock_test_and_set", KW___SYNC_LOCK_TEST_AND_SET}, +#line 30 "kw.gperf" + {"float", KW_FLOAT}, + {""}, {""}, {""}, +#line 131 "kw.gperf" + {"__sync_lock_release", KW___SYNC_LOCK_RELEASE}, + {""}, +#line 112 "kw.gperf" + {"~", KW_TILDE}, + {""}, {""}, +#line 34 "kw.gperf" + {"enum", KW_ENUM}, + {""}, {""}, +#line 90 "kw.gperf" + {"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW}, #line 65 "kw.gperf" {"volatile", KW_VOLATILE}, - {""}, {""}, {""}, -#line 21 "kw.gperf" - {"do", KW_DO}, - {""}, + {""}, {""}, +#line 106 "kw.gperf" + {"}", KW_RB}, +#line 134 "kw.gperf" + {"__atomic_compare_exchange_n", KW___ATOMIC_COMPARE_EXCHANGE_N}, +#line 92 "kw.gperf" + {"__builtin_offsetof", KW___BUILTIN_OFFSETOF}, + {""}, {""}, +#line 59 "kw.gperf" + {"strlen", KW_STRLEN}, + {""}, {""}, #line 71 "kw.gperf" {"_Static_assert", KW__STATIC_ASSERT}, {""}, -#line 38 "kw.gperf" - {"ifndef", KW_IFNDEF}, - {""}, {""}, -#line 24 "kw.gperf" - {"long", KW_LONG}, - {""}, {""}, {""}, {""}, -#line 123 "kw.gperf" - {"__atomic_clear", KW___ATOMIC_CLEAR}, - {""}, -#line 32 "kw.gperf" - {"signed", KW_SIGNED}, -#line 40 "kw.gperf" - {"defined", KW_DEFINED}, - {""}, {""}, {""}, -#line 53 "kw.gperf" - {"inline", KW_INLINE}, -#line 36 "kw.gperf" - {"include", KW_INCLUDE}, - {""}, {""}, {""}, -#line 50 "kw.gperf" - {"extern", KW_EXTERN}, -#line 52 "kw.gperf" - {"include_next", KW_INCLUDE_NEXT}, - {""}, {""}, {""}, -#line 14 "kw.gperf" - {"return", KW_RETURN}, - {""}, -#line 23 "kw.gperf" - {"unsigned", KW_UNSIGNED}, -#line 46 "kw.gperf" - {"_Noreturn", KW__NORETURN}, - {""}, -#line 130 "kw.gperf" - {"__builtin_ia32_pmovmskb128", KW___BUILTIN_IA32_PMOVMSKB128}, +#line 105 "kw.gperf" + {"{", KW_LB}, #line 42 "kw.gperf" {"default", KW_DEFAULT}, - {""}, -#line 34 "kw.gperf" - {"enum", KW_ENUM}, - {""}, -#line 59 "kw.gperf" - {"strlen", KW_STRLEN}, -#line 129 "kw.gperf" - {"__builtin_ia32_movntdq", KW___BUILTIN_IA32_MOVNTDQ}, - {""}, -#line 83 "kw.gperf" - {"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED}, - {""}, -#line 27 "kw.gperf" - {"switch", KW_SWITCH}, - {""}, {""}, {""}, {""}, {""}, -#line 93 "kw.gperf" - {"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW}, - {""}, {""}, {""}, -#line 107 "kw.gperf" - {"{", KW_LB}, - {""}, #line 80 "kw.gperf" {"__thread", KW__THREAD_LOCAL}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 100 "kw.gperf" - {"__builtin_strlen", KW___BUILTIN_STRLEN}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 120 "kw.gperf" - {".", KW_DOT}, {""}, {""}, {""}, -#line 33 "kw.gperf" - {"break", KW_BREAK}, - {""}, {""}, {""}, {""}, {""}, -#line 112 "kw.gperf" +#line 128 "kw.gperf" + {"__atomic_fetch_or", KW___ATOMIC_FETCH_OR}, +#line 124 "kw.gperf" + {"__atomic_fetch_add", KW___ATOMIC_FETCH_ADD}, +#line 24 "kw.gperf" + {"long", KW_LONG}, + {""}, +#line 118 "kw.gperf" + {".", KW_DOT}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 110 "kw.gperf" {"*", KW_STAR}, {""}, -#line 121 "kw.gperf" - {"__atomic_load", KW___ATOMIC_LOAD}, +#line 126 "kw.gperf" + {"__atomic_fetch_and", KW___ATOMIC_FETCH_AND}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 106 "kw.gperf" +#line 104 "kw.gperf" {")", KW_RP}, - {""}, {""}, {""}, -#line 26 "kw.gperf" - {"union", KW_UNION}, - {""}, {""}, {""}, {""}, {""}, -#line 105 "kw.gperf" + {""}, +#line 127 "kw.gperf" + {"__atomic_fetch_xor", KW___ATOMIC_FETCH_XOR}, + {""}, {""}, +#line 53 "kw.gperf" + {"inline", KW_INLINE}, + {""}, {""}, {""}, {""}, +#line 103 "kw.gperf" {"(", KW_LP}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 113 "kw.gperf" +#line 111 "kw.gperf" {"!", KW_EXCLAIM}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 36 "kw.gperf" + {"include", KW_INCLUDE}, + {""}, {""}, {""}, {""}, +#line 132 "kw.gperf" + {"__builtin_ia32_movntdq", KW___BUILTIN_IA32_MOVNTDQ}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 125 "kw.gperf" - {"__atomic_fetch_add", KW___ATOMIC_FETCH_ADD}, - {""}, {""}, {""}, {""}, -#line 124 "kw.gperf" - {"__atomic_sub_fetch", KW___ATOMIC_SUB_FETCH} + {"__atomic_fetch_sub", KW___ATOMIC_FETCH_SUB}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 52 "kw.gperf" + {"include_next", KW_INCLUDE_NEXT}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 33 "kw.gperf" + {"break", KW_BREAK}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 133 "kw.gperf" + {"__builtin_ia32_pmovmskb128", KW___BUILTIN_IA32_PMOVMSKB128} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index 35b1f2e1e..b9bd06d7a 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -3121,6 +3121,33 @@ static Node *generic_selection(Token **rest, Token *tok) { return ret; } +static Node *ParseAtomic2(NodeKind kind, Token *tok, Token **rest) { + Node *node = new_node(kind, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + add_type(node->lhs); + node->ty = node->lhs->ty->base; + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; +} + +static Node *ParseAtomic3(NodeKind kind, Token *tok, Token **rest) { + Node *node = new_node(kind, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + add_type(node->lhs); + node->ty = node->lhs->ty->base; + tok = skip(tok, ','); + node->rhs = assign(&tok, tok); + add_type(node->rhs); + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; +} + // primary = "(" "{" stmt+ "}" ")" // | "(" expr ")" // | "sizeof" "(" type-name ")" @@ -3228,104 +3255,65 @@ static Node *primary(Token **rest, Token *tok) { if (is_flonum(ty)) return new_int(1, start); return new_int(2, start); } - if (kw == KW___BUILTIN_COMPARE_AND_SWAP) { + if (kw == KW___ATOMIC_COMPARE_EXCHANGE_N) { Node *node = new_node(ND_CAS, tok); tok = skip(tok->next, '('); node->cas_addr = assign(&tok, tok); + add_type(node->cas_addr); tok = skip(tok, ','); node->cas_old = assign(&tok, tok); + add_type(node->cas_old); tok = skip(tok, ','); node->cas_new = assign(&tok, tok); + add_type(node->cas_new); + tok = skip(tok, ','); + /* weak = */ const_expr(&tok, tok); + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); + tok = skip(tok, ','); + /* memorder_failure = */ const_expr(&tok, tok); *rest = skip(tok, ')'); node->ty = node->cas_addr->ty->base; return node; } - if (kw == KW___ATOMIC_EXCHANGE) { - Node *node = new_node(ND_EXCH, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->rhs = assign(&tok, tok); - *rest = skip(tok, ')'); - return node; + if (kw == KW___ATOMIC_EXCHANGE_N) { + return ParseAtomic3(ND_EXCH_N, tok, rest); } if (kw == KW___ATOMIC_LOAD) { - Node *node = new_node(ND_LOAD, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->rhs = assign(&tok, tok); - tok = skip(tok, ','); - node->memorder = const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + return ParseAtomic3(ND_LOAD, tok, rest); } if (kw == KW___ATOMIC_STORE) { - Node *node = new_node(ND_STORE, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->rhs = assign(&tok, tok); - tok = skip(tok, ','); - node->memorder = const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + return ParseAtomic3(ND_STORE, tok, rest); } - if (kw == KW___ATOMIC_TEST_AND_SET) { - Node *node = new_node(ND_TESTANDSETA, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->memorder = const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + if (kw == KW___ATOMIC_LOAD_N) { + return ParseAtomic2(ND_LOAD_N, tok, rest); } - if (kw == KW___ATOMIC_CLEAR) { - Node *node = new_node(ND_CLEAR, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->memorder = const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + if (kw == KW___ATOMIC_STORE_N) { + return ParseAtomic3(ND_STORE_N, tok, rest); } if (kw == KW___ATOMIC_FETCH_ADD) { - Node *node = new_node(ND_FETCHADD, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->rhs = assign(&tok, tok); - tok = skip(tok, ','); - const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + return ParseAtomic3(ND_FETCHADD, tok, rest); } - if (kw == KW___ATOMIC_SUB_FETCH) { - Node *node = new_node(ND_SUBFETCH, tok); - tok = skip(tok->next, '('); - node->lhs = assign(&tok, tok); - add_type(node->lhs); - node->ty = node->lhs->ty->base; - tok = skip(tok, ','); - node->rhs = assign(&tok, tok); - tok = skip(tok, ','); - const_expr(&tok, tok); - *rest = skip(tok, ')'); - return node; + if (kw == KW___ATOMIC_FETCH_SUB) { + return ParseAtomic3(ND_FETCHSUB, tok, rest); + } + if (kw == KW___ATOMIC_FETCH_XOR) { + return ParseAtomic3(ND_FETCHXOR, tok, rest); + } + if (kw == KW___ATOMIC_FETCH_AND) { + return ParseAtomic3(ND_FETCHAND, tok, rest); + } + if (kw == KW___ATOMIC_FETCH_OR) { + return ParseAtomic3(ND_FETCHOR, tok, rest); + } + if (kw == KW___ATOMIC_TEST_AND_SET) { + return ParseAtomic2(ND_TESTANDSETA, tok, rest); + } + if (kw == KW___ATOMIC_CLEAR) { + return ParseAtomic2(ND_CLEAR, tok, rest); } if (kw == KW___SYNC_LOCK_TEST_AND_SET) { + // TODO(jart): delete me Node *node = new_node(ND_TESTANDSET, tok); tok = skip(tok->next, '('); node->lhs = assign(&tok, tok); @@ -3337,6 +3325,7 @@ static Node *primary(Token **rest, Token *tok) { return node; } if (kw == KW___SYNC_LOCK_RELEASE) { + // TODO(jart): delete me Node *node = new_node(ND_RELEASE, tok); tok = skip(tok->next, '('); node->lhs = assign(&tok, tok); diff --git a/third_party/chibicc/test/asm_test.c b/third_party/chibicc/test/asm_test.c index 8521da8d6..2364ea804 100644 --- a/third_party/chibicc/test/asm_test.c +++ b/third_party/chibicc/test/asm_test.c @@ -83,6 +83,24 @@ void testFlagOutputs(void) { ASSERT(false, sf); } +void testAugmentLoByte_onlyModifiesLowerBits(void) { + int x, y; + x = 0x01020304; + y = 0x00000005; + asm("sub\t%b1,%b0" : "+q"(x) : "q"(y)); + ASSERT(0x010203ff, x); + ASSERT(0x00000005, y); +} + +void testAugmentHiByte_onlyModifiesHigherBits(void) { + int x, y; + x = 0x01020304; + y = 0x00000400; + asm("sub\t%h1,%h0" : "+Q"(x) : "Q"(y)); + ASSERT(0x0102ff04, x); + ASSERT(0x00000400, y); +} + int main() { ASSERT(50, asm_fn1()); ASSERT(55, asm_fn2()); @@ -135,5 +153,8 @@ int main() { ASSERT(1, !strcmp(p, "hello")); } + testAugmentLoByte_onlyModifiesLowerBits(); + testAugmentHiByte_onlyModifiesHigherBits(); + return 0; } diff --git a/third_party/chibicc/test/atomic_test.c b/third_party/chibicc/test/atomic_test.c new file mode 100644 index 000000000..537b2367c --- /dev/null +++ b/third_party/chibicc/test/atomic_test.c @@ -0,0 +1,41 @@ +#include "third_party/chibicc/test/test.h" + +_Atomic(int) lock; + +main() { + int x; + + ASSERT(0, __atomic_exchange_n(&lock, 1, __ATOMIC_SEQ_CST)); + __atomic_load(&lock, &x, __ATOMIC_SEQ_CST); + ASSERT(1, x); + ASSERT(1, __atomic_exchange_n(&lock, 2, __ATOMIC_SEQ_CST)); + ASSERT(2, __atomic_exchange_n(&lock, 3, __ATOMIC_SEQ_CST)); + ASSERT(3, __atomic_load_n(&lock, __ATOMIC_SEQ_CST)); + __atomic_store_n(&lock, 0, __ATOMIC_SEQ_CST); + ASSERT(0, __atomic_fetch_xor(&lock, 3, __ATOMIC_SEQ_CST)); + ASSERT(3, __atomic_fetch_xor(&lock, 1, __ATOMIC_SEQ_CST)); + ASSERT(2, __atomic_load_n(&lock, __ATOMIC_SEQ_CST)); + + // CAS success #1 + x = 2; + ASSERT(1, __atomic_compare_exchange_n(&lock, &x, 3, 0, __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST)); + ASSERT(2, x); + ASSERT(3, lock); + + // CAS success #2 + x = 3; + ASSERT(1, __atomic_compare_exchange_n(&lock, &x, 4, 0, __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST)); + ASSERT(3, x); + ASSERT(4, lock); + + // CAS fail + x = 3; + ASSERT(0, __atomic_compare_exchange_n(&lock, &x, 7, 0, __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST)); + ASSERT(4, x); + ASSERT(4, lock); + + // +} diff --git a/third_party/chibicc/type.c b/third_party/chibicc/type.c index 5ddac510d..ecc44fe7a 100644 --- a/third_party/chibicc/type.c +++ b/third_party/chibicc/type.c @@ -294,9 +294,16 @@ void add_type(Node *node) { if (node->cas_old->ty->kind != TY_PTR) error_tok(node->cas_old->tok, "pointer expected"); return; - case ND_EXCH: + case ND_EXCH_N: + case ND_FETCHADD: + case ND_FETCHSUB: + case ND_FETCHXOR: + case ND_FETCHAND: + case ND_FETCHOR: + case ND_SUBFETCH: if (node->lhs->ty->kind != TY_PTR) - error_tok(node->cas_addr->tok, "pointer expected"); + error_tok(node->lhs->tok, "pointer expected"); + node->rhs = new_cast(node->rhs, node->lhs->ty->base); node->ty = node->lhs->ty->base; return; } diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index 35b449947..86e36e84b 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -164,9 +164,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode) { struct ElfWriter *elf; CHECK_NOTNULL((elf = calloc(1, sizeof(struct ElfWriter)))); CHECK_NOTNULL((elf->path = strdup(path))); - CHECK_NE(-1, asprintf(&elf->tmppath, "%s.%d", elf->path, getpid())); - CHECK_NE(-1, (elf->fd = open(elf->tmppath, - O_CREAT | O_TRUNC | O_RDWR | O_EXCL, mode))); + CHECK_NE(-1, (elf->fd = open(elf->path, O_CREAT | O_TRUNC | O_RDWR, mode))); CHECK_NE(-1, ftruncate(elf->fd, (elf->mapsize = FRAMESIZE))); CHECK_NE(MAP_FAILED, (elf->map = mmap((void *)(intptr_t)kFixedmapStart, elf->mapsize, PROT_READ | PROT_WRITE, @@ -187,7 +185,6 @@ void elfwriter_close(struct ElfWriter *elf) { CHECK_NE(-1, munmap(elf->map, elf->mapsize)); CHECK_NE(-1, ftruncate(elf->fd, elf->wrote)); CHECK_NE(-1, close(elf->fd)); - CHECK_NE(-1, rename(elf->tmppath, elf->path)); freeinterner(elf->shstrtab); freeinterner(elf->strtab); free(elf->shdrs->p); diff --git a/tool/build/lib/elfwriter.h b/tool/build/lib/elfwriter.h index 62b3277c1..151b88d06 100644 --- a/tool/build/lib/elfwriter.h +++ b/tool/build/lib/elfwriter.h @@ -34,7 +34,6 @@ struct ElfWriterRela { struct ElfWriter { char *path; - char *tmppath; int fd; void *map; size_t mapsize; diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 7958f88ca..73de05ddb 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -833,11 +833,11 @@ static void DescribeAddress(char buf[40], uint32_t addr, uint16_t port) { char *p; const char *s; p = buf; - p = FormatUint64(p, (addr & 0xFF000000) >> 030), *p++ = '.'; - p = FormatUint64(p, (addr & 0x00FF0000) >> 020), *p++ = '.'; - p = FormatUint64(p, (addr & 0x0000FF00) >> 010), *p++ = '.'; - p = FormatUint64(p, (addr & 0x000000FF) >> 000), *p++ = ':'; - p = FormatUint64(p, port); + p = FormatUint32(p, (addr & 0xFF000000) >> 030), *p++ = '.'; + p = FormatUint32(p, (addr & 0x00FF0000) >> 020), *p++ = '.'; + p = FormatUint32(p, (addr & 0x0000FF00) >> 010), *p++ = '.'; + p = FormatUint32(p, (addr & 0x000000FF) >> 000), *p++ = ':'; + p = FormatUint32(p, port); *p = '\0'; assert(p - buf < 40); }