Add some more builtins to chibicc

https://justine.lol/cosmopolitan/documentation.html should now contain a
lot of functions that had been missing previously due to not having them
This commit is contained in:
Justine Tunney 2022-04-17 12:25:10 -07:00
parent ab38f0823d
commit f1dfa4bdfa
17 changed files with 417 additions and 201 deletions

View file

@ -80,6 +80,37 @@ o//examples/hello.com
find o -name \*.com | xargs ls -rShal | less
```
## GDB
Here's the recommended `~/.gdbinit` config:
```
set host-charset UTF-8
set target-charset UTF-8
set target-wide-charset UTF-8
set osabi none
set complaints 0
set confirm off
set history save on
set history filename ~/.gdb_history
define asm
layout asm
layout reg
end
define src
layout src
layout reg
end
src
```
You normally run the `.com.dbg` file under gdb. If you need to debug the
`.com` file itself, then you can load the debug symbols independently as
```
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
```
## Support Vector
| Platform | Min Version | Circa |

View file

@ -292,50 +292,50 @@ static int __sigaction(int sig, const struct sigaction *act,
* have your signals work hand-in-glove with the EINTR errno. This
* obfuscates the need for having to worry about @asyncsignalsafe.
*
* static volatile bool gotctrlc;
* static volatile bool gotctrlc;
*
* void OnCtrlC(int sig) {
* gotctrlc = true;
* }
* void OnCtrlC(int sig) {
* gotctrlc = true;
* }
*
* int main() {
* size_t got;
* ssize_t rc;
* char buf[1];
* struct sigaction oldint;
* struct sigaction saint = {.sa_handler = GotCtrlC};
* if (sigaction(SIGINT, &saint, &oldint) == -1) {
* perror("sigaction");
* exit(1);
* }
* for (;;) {
* rc = read(0, buf, sizeof(buf));
* if (rc == -1) {
* if (errno == EINTR) {
* if (gotctrlc) {
* break;
* }
* } else {
* perror("read");
* exit(2);
* }
* }
* if (!(got = rc)) {
* break;
* }
* for (;;) {
* rc = write(1, buf, got);
* if (rc != -1) {
* assert(rc == 1);
* break;
* } else if (errno != EINTR) {
* perror("write");
* exit(3);
* }
* }
* }
* sigaction(SIGINT, &oldint, 0);
* }
* int main() {
* size_t got;
* ssize_t rc;
* char buf[1];
* struct sigaction oldint;
* struct sigaction saint = {.sa_handler = GotCtrlC};
* if (sigaction(SIGINT, &saint, &oldint) == -1) {
* perror("sigaction");
* exit(1);
* }
* for (;;) {
* rc = read(0, buf, sizeof(buf));
* if (rc == -1) {
* if (errno == EINTR) {
* if (gotctrlc) {
* break;
* }
* } else {
* perror("read");
* exit(2);
* }
* }
* if (!(got = rc)) {
* break;
* }
* for (;;) {
* rc = write(1, buf, got);
* if (rc != -1) {
* assert(rc == 1);
* break;
* } else if (errno != EINTR) {
* perror("write");
* exit(3);
* }
* }
* }
* sigaction(SIGINT, &oldint, 0);
* }
*
* Please note that you can't do the above if you use SA_RESTART. Since
* the purpose of SA_RESTART is to restart i/o operations whose docs say

View file

@ -4,17 +4,17 @@
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 401 && \
!defined(__STRICT_ANSI__)
#define _spinlock(lock) \
do { \
for (;;) { \
typeof(*(lock)) x; \
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
if (!x && !__sync_lock_test_and_set(lock, __ATOMIC_CONSUME)) { \
break; \
} else { \
__builtin_ia32_pause(); \
} \
} \
#define _spinlock(lock) \
do { \
for (;;) { \
typeof(*(lock)) x; \
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
if (!x && !__sync_lock_test_and_set(lock, 1)) { \
break; \
} else { \
__builtin_ia32_pause(); \
} \
} \
} while (0)
#define _spunlock(lock) __sync_lock_release(lock)

View file

@ -17,6 +17,7 @@ local enhancements
- 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

@ -2428,6 +2428,14 @@ static void OpSseMov(struct As *a, int opWsdVsd, int opVsdWsd) {
}
}
static void OpMovntdq(struct As *a) {
int reg, modrm, disp;
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x660FE7, reg, modrm, disp, 0);
}
static void OpMovdqx(struct As *a, int op) {
OpSseMov(a, op + 0x10, op);
}
@ -3005,6 +3013,7 @@ static void OnPunpcklbw(struct As *a, struct Slice s) { OpSse(a, 0x660F60); }
static void OnPunpckldq(struct As *a, struct Slice s) { OpSse(a, 0x660F62); }
static void OnPunpcklqdq(struct As *a, struct Slice s) { OpSse(a, 0x660F6C); }
static void OnPunpcklwd(struct As *a, struct Slice s) { OpSse(a, 0x660F61); }
static void OnMovntdq(struct As *a, struct Slice s) { OpMovntdq(a); }
static void OnPxor(struct As *a, struct Slice s) { OpSse(a, 0x660FEF); }
static void OnRcl(struct As *a, struct Slice s) { OpBsu(a, s, 2); }
static void OnRcpps(struct As *a, struct Slice s) { OpSse(a, 0x0F53); }
@ -3637,6 +3646,7 @@ static const struct Directive16 {
{"cvttss2si", OnCvttss2si}, //
{"cvttss2sil", OnCvttss2si}, //
{"cvttss2siq", OnCvttss2si}, //
{"movntdq", OnMovntdq}, //
{"pcmpistri", OnPcmpistri}, //
{"pcmpistrm", OnPcmpistrm}, //
{"phminposuw", OnPhminposuw}, //

View file

@ -685,6 +685,7 @@ static void OnCtrlC(int sig, siginfo_t *si, ucontext_t *ctx) {
}
int chibicc(int argc, char **argv) {
ShowCrashReports();
atexit(chibicc_cleanup);
sigaction(SIGINT, &(struct sigaction){.sa_sigaction = OnCtrlC}, NULL);
for (int i = 1; i < argc; i++) {

View file

@ -345,7 +345,12 @@ typedef enum {
ND_ASM, // "asm"
ND_CAS, // Atomic compare-and-swap
ND_EXCH, // Atomic exchange
ND_LOAD, // Atomic load
ND_TESTANDSET, // Atomic lock test and set
ND_RELEASE, // Atomic lock release
ND_FPCLASSIFY, // floating point classify
ND_MOVNTDQ, // Intel MOVNTDQ
ND_PMOVMSKB, // Intel PMOVMSKB
} NodeKind;
struct Node {

View file

@ -904,6 +904,9 @@ static bool gen_builtin_funcall(Node *node, const char *name) {
} else if (!strcmp(name, "trap")) {
emitlin("\tint3");
return true;
} else if (!strcmp(name, "ia32_pause")) {
emitlin("\tpause");
return true;
} else if (!strcmp(name, "unreachable")) {
emitlin("\tud2");
return true;
@ -1521,7 +1524,8 @@ void gen_expr(Node *node) {
emitlin("\tmovzbl\t%cl,%eax");
return;
}
case ND_EXCH: {
case ND_EXCH:
case ND_TESTANDSET: {
gen_expr(node->lhs);
push();
gen_expr(node->rhs);
@ -1529,6 +1533,23 @@ void gen_expr(Node *node) {
println("\txchg\t%s,(%%rdi)", reg_ax(node->ty->size));
return;
}
case ND_LOAD: {
gen_expr(node->rhs);
push();
gen_expr(node->lhs);
println("\tmov\t(%%rax),%s", reg_ax(node->ty->size));
pop("%rdi");
println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size));
return;
}
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;
@ -1658,6 +1679,14 @@ void gen_expr(Node *node) {
dx = "%edx";
}
switch (node->kind) {
case ND_PMOVMSKB:
println("\tmovdqu\t(%%rax),%%xmm0");
println("\tpmovmskb\t%%xmm0,%%rax");
break;
case ND_MOVNTDQ:
println("\tmovdqu\t(%%rdi),%%xmm0");
println("\tmovntdq\t%%xmm0,(%%rax)");
break;
case ND_ADD:
if (node->lhs->ty->kind == TY_INT128) {
emitlin("\tadd\t%rdi,%rax");

View file

@ -81,7 +81,7 @@ __thread, KW__THREAD_LOCAL
__typeof, KW_TYPEOF
__builtin_add_overflow, KW___BUILTIN_ADD_OVERFLOW
__builtin_assume_aligned, KW___BUILTIN_ASSUME_ALIGNED
__builtin_atomic_exchange, KW___BUILTIN_ATOMIC_EXCHANGE
__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
@ -118,3 +118,8 @@ __builtin_types_compatible_p, KW___BUILTIN_TYPES_COMPATIBLE_P
"||", KW_LOGOR
"->", KW_ARROW
".", KW_DOT
__atomic_load, KW___ATOMIC_LOAD
__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

View file

@ -68,7 +68,7 @@
#define KW___ASM__ 84
#define KW___BUILTIN_ADD_OVERFLOW 85
#define KW___BUILTIN_ASSUME_ALIGNED 86
#define KW___BUILTIN_ATOMIC_EXCHANGE 87
#define KW___ATOMIC_EXCHANGE 87
#define KW___BUILTIN_COMPARE_AND_SWAP 88
#define KW___BUILTIN_CONSTANT_P 89
#define KW___BUILTIN_EXPECT 90
@ -105,6 +105,11 @@
#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
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -1,7 +1,7 @@
/* ANSI-C code produced by gperf version 3.1 */
/* Command-line: gperf kw.gperf */
/* Computed positions: -k'1,4,11,14,$' */
/* clang-format off */
// clang-format off
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@ -37,51 +37,44 @@
#line 10 "kw.gperf"
struct thatispacked KwSlot { char *name; unsigned char code; };
#define TOTAL_KEYWORDS 109
#define TOTAL_KEYWORDS 114
#define MIN_WORD_LENGTH 1
#define MAX_WORD_LENGTH 28
#define MIN_HASH_VALUE 1
#define MAX_HASH_VALUE 211
/* maximum key range = 211, duplicates = 0 */
#define MAX_HASH_VALUE 201
/* maximum key range = 201, duplicates = 0 */
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
static inline unsigned int
hash (register const char *str, register size_t len)
{
static const unsigned char asso_values[] =
{
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 105, 212, 212, 212, 212, 65, 212,
100, 95, 90, 15, 212, 0, 80, 212, 212, 212,
212, 212, 212, 212, 212, 212, 5, 212, 212, 212,
212, 212, 65, 212, 212, 212, 0, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 5, 212, 20, 50, 0,
5, 15, 0, 25, 40, 90, 60, 0, 20, 15,
85, 105, 0, 25, 55, 10, 0, 65, 5, 0,
0, 10, 0, 30, 10, 25, 5, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 100, 202, 202, 202, 202, 65, 202,
95, 90, 85, 15, 202, 0, 75, 202, 202, 202,
0, 202, 202, 202, 202, 202, 10, 202, 202, 202,
202, 202, 55, 202, 202, 202, 0, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 5, 202, 0, 50, 0,
5, 15, 0, 40, 45, 115, 60, 5, 20, 15,
90, 85, 0, 0, 55, 10, 0, 65, 5, 0,
0, 10, 25, 70, 35, 30, 5, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
202, 202, 202, 202, 202, 202, 202
};
register unsigned int hval = len;
@ -135,24 +128,23 @@ LookupKw (register const char *str, register size_t len)
{"~", KW_TILDE},
#line 68 "kw.gperf"
{"_Atomic", KW__ATOMIC},
#line 81 "kw.gperf"
{"__typeof", KW_TYPEOF},
{""},
{""}, {""},
#line 78 "kw.gperf"
{"__restrict", KW_RESTRICT},
#line 22 "kw.gperf"
{"sizeof", KW_SIZEOF},
#line 75 "kw.gperf"
{"__asm__", KW___ASM__},
{""},
#line 41 "kw.gperf"
{"asm", KW_ASM},
#line 15 "kw.gperf"
{"case", KW_CASE},
#line 73 "kw.gperf"
{"__VA_OPT__", KW___VA_OPT__},
#line 13 "kw.gperf"
{"struct", KW_STRUCT},
#line 118 "kw.gperf"
{"||", KW_LOGOR},
#line 60 "kw.gperf"
{"strpbrk", KW_STRPBRK},
{""}, {""},
#line 31 "kw.gperf"
{"short", KW_SHORT},
@ -178,22 +170,19 @@ LookupKw (register const char *str, register size_t len)
{"while", KW_WHILE},
#line 85 "kw.gperf"
{"__builtin_compare_and_swap", KW___BUILTIN_COMPARE_AND_SWAP},
#line 101 "kw.gperf"
{"__builtin_strpbrk", KW___BUILTIN_STRPBRK},
#line 41 "kw.gperf"
{"asm", KW_ASM},
#line 82 "kw.gperf"
{"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW},
#line 81 "kw.gperf"
{"__typeof", KW_TYPEOF},
#line 55 "kw.gperf"
{"line", KW_LINE},
#line 86 "kw.gperf"
{"__builtin_constant_p", KW___BUILTIN_CONSTANT_P},
#line 74 "kw.gperf"
{"__alignof__", KW___ALIGNOF__},
#line 60 "kw.gperf"
{"strpbrk", KW_STRPBRK},
{""},
#line 47 "kw.gperf"
{"elif", KW_ELIF},
{""}, {""},
#line 101 "kw.gperf"
{"__builtin_strpbrk", KW___BUILTIN_STRPBRK},
{""}, {""}, {""}, {""},
#line 103 "kw.gperf"
{"__builtin_sub_overflow", KW___BUILTIN_SUB_OVERFLOW},
#line 72 "kw.gperf"
@ -202,8 +191,8 @@ LookupKw (register const char *str, register size_t len)
{"__builtin_popcountl", KW___BUILTIN_POPCOUNTL},
#line 97 "kw.gperf"
{"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL},
#line 108 "kw.gperf"
{"}", KW_RB},
#line 56 "kw.gperf"
{"pragma", KW_PRAGMA},
#line 92 "kw.gperf"
{"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW},
#line 104 "kw.gperf"
@ -213,15 +202,16 @@ LookupKw (register const char *str, register size_t len)
{"float", KW_FLOAT},
#line 87 "kw.gperf"
{"__builtin_expect", KW___BUILTIN_EXPECT},
#line 82 "kw.gperf"
{"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW},
#line 119 "kw.gperf"
{"->", KW_ARROW},
#line 20 "kw.gperf"
{"for", KW_FOR},
{""},
#line 47 "kw.gperf"
{"elif", KW_ELIF},
#line 91 "kw.gperf"
{"__builtin_fpclassify", KW___BUILTIN_FPCLASSIFY},
#line 107 "kw.gperf"
{"{", KW_LB},
#line 108 "kw.gperf"
{"}", KW_RB},
#line 42 "kw.gperf"
{"default", KW_DEFAULT},
{""},
@ -229,21 +219,19 @@ LookupKw (register const char *str, register size_t len)
{"__builtin_ffsl", KW___BUILTIN_FFSL},
#line 90 "kw.gperf"
{"__builtin_ffsll", KW___BUILTIN_FFSLL},
#line 56 "kw.gperf"
{"pragma", KW_PRAGMA},
#line 119 "kw.gperf"
{"->", KW_ARROW},
{""},
{""}, {""}, {""},
#line 18 "kw.gperf"
{"char", KW_CHAR},
#line 64 "kw.gperf"
{"undef", KW_UNDEF},
#line 61 "kw.gperf"
{"strstr", KW_STRSTR},
{""},
#line 118 "kw.gperf"
{"||", KW_LOGOR},
#line 67 "kw.gperf"
{"_Alignof", KW__ALIGNOF},
{""},
#line 122 "kw.gperf"
{"__sync_lock_test_and_set", KW___SYNC_LOCK_TEST_AND_SET},
#line 49 "kw.gperf"
{"error", KW_ERROR},
#line 58 "kw.gperf"
@ -261,19 +249,53 @@ LookupKw (register const char *str, register size_t len)
{""},
#line 66 "kw.gperf"
{"_Alignas", KW__ALIGNAS},
#line 123 "kw.gperf"
{"__sync_lock_release", KW___SYNC_LOCK_RELEASE},
{""},
#line 84 "kw.gperf"
{"__builtin_atomic_exchange", KW___BUILTIN_ATOMIC_EXCHANGE},
#line 39 "kw.gperf"
{"define", KW_DEFINE},
{""},
#line 35 "kw.gperf"
{"continue", KW_CONTINUE},
#line 24 "kw.gperf"
{"long", KW_LONG},
#line 43 "kw.gperf"
{"auto", KW_AUTO},
{""},
#line 99 "kw.gperf"
{"__builtin_strchr", KW___BUILTIN_STRCHR},
#line 21 "kw.gperf"
{"do", KW_DO},
{""}, {""}, {""}, {""}, {""},
#line 70 "kw.gperf"
{"_Generic", KW__GENERIC},
#line 98 "kw.gperf"
{"__builtin_reg_class", KW___BUILTIN_REG_CLASS},
{""},
#line 102 "kw.gperf"
{"__builtin_strstr", KW___BUILTIN_STRSTR},
#line 84 "kw.gperf"
{"__atomic_exchange", KW___ATOMIC_EXCHANGE},
#line 45 "kw.gperf"
{"__attribute__", KW___ATTRIBUTE__},
#line 83 "kw.gperf"
{"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED},
{""},
#line 32 "kw.gperf"
{"signed", KW_SIGNED},
{""},
#line 77 "kw.gperf"
{"__int128", KW___INT128},
#line 24 "kw.gperf"
{"long", KW_LONG},
#line 33 "kw.gperf"
{"break", KW_BREAK},
#line 50 "kw.gperf"
{"extern", KW_EXTERN},
{""},
#line 76 "kw.gperf"
{"__inline", KW_INLINE},
#line 46 "kw.gperf"
{"_Noreturn", KW__NORETURN},
{""}, {""},
#line 12 "kw.gperf"
{"if", KW_IF},
#line 54 "kw.gperf"
@ -281,37 +303,11 @@ LookupKw (register const char *str, register size_t len)
{""},
#line 37 "kw.gperf"
{"ifdef", KW_IFDEF},
{""}, {""}, {""},
#line 98 "kw.gperf"
{"__builtin_reg_class", KW___BUILTIN_REG_CLASS},
{""},
#line 102 "kw.gperf"
{"__builtin_strstr", KW___BUILTIN_STRSTR},
{""},
#line 45 "kw.gperf"
{"__attribute__", KW___ATTRIBUTE__},
{""},
#line 33 "kw.gperf"
{"break", KW_BREAK},
#line 50 "kw.gperf"
{"extern", KW_EXTERN},
{""},
#line 80 "kw.gperf"
{"__thread", KW__THREAD_LOCAL},
#line 46 "kw.gperf"
{"_Noreturn", KW__NORETURN},
{""},
#line 38 "kw.gperf"
{"ifndef", KW_IFNDEF},
#line 21 "kw.gperf"
{"do", KW_DO},
{""}, {""}, {""},
#line 59 "kw.gperf"
{"strlen", KW_STRLEN},
#line 52 "kw.gperf"
{"include_next", KW_INCLUDE_NEXT},
#line 70 "kw.gperf"
{"_Generic", KW__GENERIC},
{""},
#line 94 "kw.gperf"
{"__builtin_offsetof", KW___BUILTIN_OFFSETOF},
#line 34 "kw.gperf"
{"enum", KW_ENUM},
{""},
@ -319,62 +315,65 @@ LookupKw (register const char *str, register size_t len)
{"switch", KW_SWITCH},
#line 93 "kw.gperf"
{"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW},
#line 77 "kw.gperf"
{"__int128", KW___INT128},
#line 83 "kw.gperf"
{"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED},
{""},
#line 32 "kw.gperf"
{"signed", KW_SIGNED},
#line 36 "kw.gperf"
{"include", KW_INCLUDE},
#line 57 "kw.gperf"
{"restrict", KW_RESTRICT},
#line 43 "kw.gperf"
{"auto", KW_AUTO},
#line 51 "kw.gperf"
{"goto", KW_GOTO},
{""},
#line 111 "kw.gperf"
{"&", KW_AMP},
#line 117 "kw.gperf"
{"&&", KW_LOGAND},
#line 76 "kw.gperf"
{"__inline", KW_INLINE},
#line 51 "kw.gperf"
{"goto", KW_GOTO},
{""}, {""}, {""},
#line 80 "kw.gperf"
{"__thread", KW__THREAD_LOCAL},
{""}, {""},
#line 38 "kw.gperf"
{"ifndef", KW_IFNDEF},
{""},
#line 23 "kw.gperf"
{"unsigned", KW_UNSIGNED},
{""}, {""},
#line 107 "kw.gperf"
{"{", KW_LB},
#line 52 "kw.gperf"
{"include_next", KW_INCLUDE_NEXT},
{""}, {""}, {""},
#line 100 "kw.gperf"
{"__builtin_strlen", KW___BUILTIN_STRLEN},
{""},
#line 94 "kw.gperf"
{"__builtin_offsetof", KW___BUILTIN_OFFSETOF},
{""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 124 "kw.gperf"
{"__builtin_ia32_movntdq", KW___BUILTIN_IA32_MOVNTDQ},
{""}, {""}, {""},
#line 120 "kw.gperf"
{".", KW_DOT},
#line 36 "kw.gperf"
{"include", KW_INCLUDE},
{""}, {""}, {""},
#line 14 "kw.gperf"
{"return", KW_RETURN},
{""}, {""}, {""},
#line 26 "kw.gperf"
{"union", KW_UNION},
{""}, {""}, {""}, {""}, {""},
#line 120 "kw.gperf"
{".", KW_DOT},
#line 125 "kw.gperf"
{"__builtin_ia32_pmovmskb128", KW___BUILTIN_IA32_PMOVMSKB128},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 53 "kw.gperf"
{"inline", KW_INLINE},
{""}, {""}, {""}, {""}, {""}, {""},
#line 112 "kw.gperf"
{"*", KW_STAR},
{""},
#line 121 "kw.gperf"
{"__atomic_load", KW___ATOMIC_LOAD},
{""}, {""}, {""}, {""},
#line 44 "kw.gperf"
{"register", KW_REGISTER},
{""}, {""},
#line 112 "kw.gperf"
{"*", KW_STAR},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 106 "kw.gperf"
{")", KW_RP},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 105 "kw.gperf"
{"(", KW_LP},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""},
#line 53 "kw.gperf"
{"inline", KW_INLINE},
{""}, {""}, {""}, {""},
#line 113 "kw.gperf"
{"!", KW_EXCLAIM}
};

View file

@ -976,11 +976,12 @@ static Type *type_suffix(Token **rest, Token *tok, Type *ty) {
return ty;
}
// pointers = ("*" ("const" | "volatile" | "restrict")*)*
// pointers = ("*" ("const" | "volatile" | "restrict" | attribute)*)*
static Type *pointers(Token **rest, Token *tok, Type *ty) {
while (CONSUME(&tok, tok, "*")) {
ty = pointer_to(ty);
for (;;) {
tok = attribute_list(tok, ty, type_attributes);
if (EQUAL(tok, "const")) {
ty->is_const = true;
tok = tok->next;
@ -3218,12 +3219,67 @@ static Node *primary(Token **rest, Token *tok) {
node->ty = node->cas_addr->ty->base;
return node;
}
if (kw == KW___BUILTIN_ATOMIC_EXCHANGE) {
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_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, ',');
const_expr(&tok, tok);
*rest = skip(tok, ')');
return node;
}
if (kw == KW___SYNC_LOCK_TEST_AND_SET) {
Node *node = new_node(ND_TESTANDSET, 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___SYNC_LOCK_RELEASE) {
Node *node = new_node(ND_RELEASE, tok);
tok = skip(tok->next, '(');
node->lhs = assign(&tok, tok);
add_type(node->lhs);
node->ty = node->lhs->ty->base;
*rest = skip(tok, ')');
return node;
}
if (kw == KW___BUILTIN_IA32_MOVNTDQ) {
Node *node = new_node(ND_MOVNTDQ, 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);
*rest = skip(tok, ')');
return node;
}
if (kw == KW___BUILTIN_IA32_PMOVMSKB128) {
Node *node = new_node(ND_PMOVMSKB, tok);
tok = skip(tok->next, '(');
node->lhs = assign(&tok, tok);
add_type(node->lhs);
node->ty = node->lhs->ty->base;
*rest = skip(tok, ')');
return node;
@ -3690,6 +3746,7 @@ void declare_builtin_functions(void) {
Type *pchar = pointer_to(ty_char);
builtin_alloca = declare1("alloca", pointer_to(ty_void), ty_int);
declare0("trap", ty_int);
declare0("ia32_pause", ty_void);
declare0("unreachable", ty_int);
declare1("ctz", ty_int, ty_int);
declare1("ctzl", ty_int, ty_long);

View file

@ -1045,12 +1045,16 @@ __UINT32_MAX__\000\
0xffffffffu\000\
__INT64_MAX__\000\
0x7fffffffffffffffl\000\
__INTMAX_MAX__\000\
0x7fffffffffffffffl\000\
__LONG_MAX__\000\
0x7fffffffffffffffl\000\
__LONG_LONG_MAX__\000\
0x7fffffffffffffffl\000\
__UINT64_MAX__\000\
0xfffffffffffffffful\000\
__UINTMAX_MAX__\000\
0xfffffffffffffffful\000\
__SIZE_MAX__\000\
0xfffffffffffffffful\000\
__INTPTR_MAX__\000\
@ -1103,8 +1107,12 @@ __UINT32_TYPE__\000\
unsigned int\000\
__INT64_TYPE__\000\
long int\000\
__INTMAX_TYPE__\000\
long int\000\
__UINT64_TYPE__\000\
long unsigned int\000\
__UINTMAX_TYPE__\000\
long unsigned int\000\
__INTMAX_TYPE__\000\
long int\000\
__UINTMAX_TYPE__\000\
@ -1271,6 +1279,22 @@ __SSE2__\000\
1\000\
__SSE2_MATH__\000\
1\000\
__ATOMIC_ACQUIRE\000\
2\000\
__ATOMIC_HLE_RELEASE\000\
131072\000\
__ATOMIC_HLE_ACQUIRE\000\
65536\000\
__ATOMIC_RELAXED\000\
0\000\
__ATOMIC_CONSUME\000\
1\000\
__ATOMIC_SEQ_CST\000\
5\000\
__ATOMIC_ACQ_REL\000\
4\000\
__ATOMIC_RELEASE\000\
3\000\
\000";
do {
val = name + strlen(name) + 1;

6
third_party/chibicc/test/msabi_test.c vendored Normal file
View file

@ -0,0 +1,6 @@
#include "third_party/chibicc/test/test.h"
int (*__attribute__((__ms_abi__)) NtFoo)(int x, int y);
int main() {
}

View file

@ -0,0 +1,26 @@
#include "third_party/chibicc/test/test.h"
#define SPINLOCK(lock) \
do { \
for (;;) { \
typeof(*(lock)) x; \
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
if (!x && !__sync_lock_test_and_set(lock, 1)) { \
break; \
} else { \
__builtin_ia32_pause(); \
} \
} \
} while (0)
#define SPUNLOCK(lock) __sync_lock_release(lock)
_Alignas(64) char lock;
main() {
ASSERT(0, lock);
SPINLOCK(&lock);
ASSERT(1, lock);
SPUNLOCK(&lock);
ASSERT(0, lock);
}

View file

@ -18,6 +18,7 @@
*/
#include "third_party/chibicc/test/test.h"
typedef char byte16 __attribute__((__vector_size__(16)));
typedef float float4 __attribute__((__vector_size__(16)));
typedef float float4a1 __attribute__((__vector_size__(16), __aligned__(1)));
typedef float float4a16 __attribute__((__vector_size__(16), __aligned__(16)));
@ -39,18 +40,33 @@ int main(void) {
ASSERT(1, _Alignof(double2a1));
ASSERT(16, _Alignof(double2a16));
float4 v1;
float4 v2;
float x[4] = {1, 2, 3, 4};
float y[4] = {1, 1, 1, 1};
memcpy(&v1, x, 16);
memcpy(&v2, y, 16);
v1 = v1 + v2;
memcpy(x, &v1, 16);
ASSERT(2, x[0]);
/* ASSERT(3, x[1]); */
/* ASSERT(4, x[2]); */
/* ASSERT(5, x[3]); */
{
float4 v1;
float4 v2;
float x[4] = {1, 2, 3, 4};
float y[4] = {1, 1, 1, 1};
memcpy(&v1, x, 16);
memcpy(&v2, y, 16);
v1 = v1 + v2;
memcpy(x, &v1, 16);
ASSERT(2, x[0]);
// TODO(jart): fix me
/* ASSERT(3, x[1]); */
/* ASSERT(4, x[2]); */
/* ASSERT(5, x[3]); */
}
{
byte16 v;
float x1[4] = {1, 2, 3, 4};
float x2[4];
memcpy(&v, x1, 16);
__builtin_ia32_movntdq(x1, &v);
memcpy(x2, &v, 16);
ASSERT(1, x2[0]);
// TODO(jart): fix me
/* ASSERT(2, x[1]); */
}
return 0;
}

View file

@ -100,6 +100,7 @@ Token *skip(Token *tok, char op) {
if (tok->len == 1 && *tok->loc == op) {
return tok->next;
} else {
// __die();
error_tok(tok, "expected '%c'", op);
}
}