Add atomics to chibicc

This change also fixes #434 and makes the chibicc assembler better.
This commit is contained in:
Justine Tunney 2022-06-20 03:08:00 -07:00
parent 5ddf43332e
commit a988896048
21 changed files with 650 additions and 445 deletions

View file

@ -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_ */

43
libc/intrin/wait0.c Normal file
View file

@ -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();
}
}
}

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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

View file

@ -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}, //

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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, ...)

View file

@ -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

View file

@ -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_

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

41
third_party/chibicc/test/atomic_test.c vendored Normal file
View file

@ -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);
//
}

View file

@ -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;
}

View file

@ -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);

View file

@ -34,7 +34,6 @@ struct ElfWriterRela {
struct ElfWriter {
char *path;
char *tmppath;
int fd;
void *map;
size_t mapsize;

View file

@ -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);
}