Add chibicc

This program popped up on Hacker News recently. It's the only modern
compiler I've ever seen that doesn't have dependencies and is easily
modified. So I added all of the missing GNU extensions I like to use
which means it might be possible soon to build on non-Linux and have
third party not vendor gcc binaries.
This commit is contained in:
Justine Tunney 2020-12-05 12:20:41 -08:00
parent e44a0cf6f8
commit 8da931a7f6
298 changed files with 19493 additions and 11950 deletions

View file

@ -1,6 +1,7 @@
MIT License
Copyright (c) 2019 Rui Ueyama
Copyright (c) 2020 Justine Alexandra Roberts Tunney
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

30
third_party/chibicc/README.cosmo vendored Normal file
View file

@ -0,0 +1,30 @@
chibicc is the simplest/tiniest/hackable/readable c11 compiler in the
world that can build projects like python but goes 2x slower than gcc
with 2x the code size, because it doesn't optimize or color registers
although it can compile code at 5x the speed and could be even faster
which is great, considering it's a 220kb αcτµαlly pδrταblε εxεcµταblε
local enhancements
- support __asm__
- support __int128
- support __vector_size__
- support __builtin_memcpy
- support __builtin_constant_p, __builtin_likely, etc.
- support __builtin_isunordered, __builtin_islessgreater, etc.
- support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc.
- support __constructor__, __destructor__, __section__, __cold__, etc.
- improve error messages to trace macro expansions
- reduce #lines of generated assembly by a third
- reduce #bytes of generated binary by a third
local bug fixes
- fix 64-bit bug in generated code for struct bitfields
local changes
- use tabs in generated output
- generated code no longer assumes red zone
- emit .size directives for function definitions
- use fisttp long double conversions if built w/ -msse3

134
third_party/chibicc/README.md vendored Normal file
View file

@ -0,0 +1,134 @@
# chibicc: A Small C Compiler
(The old master has moved to
[historical/old](https://github.com/rui314/chibicc/tree/historical/old)
branch. This is a new one uploaded in September 2020.)
chibicc is yet another small C compiler that implements most C11
features. Even though it still probably falls into the "toy compilers"
category just like other small compilers do, chibicc can compile several
real-world programs, including [Git](https://git-scm.com/),
[SQLite](https://sqlite.org) and
[libpng](http://www.libpng.org/pub/png/libpng.html), without making
modifications to the compiled programs. Generated executables of these
programs pass their corresponding test suites. So, chibicc actually
supports a wide variety of C11 features and is able to compile hundreds of
thousands of lines of real-world C code correctly.
chibicc is developed as the reference implementation for a book I'm
currently writing about the C compiler and the low-level programming.
The book covers the vast topic with an incremental approach; in the first
chapter, readers will implement a "compiler" that accepts just a single
number as a "language", which will then gain one feature at a time in each
section of the book until the language that the compiler accepts matches
what the C11 spec specifies. I took this incremental approach from [the
paper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz
Ghuloum.
Each commit of this project corresponds to a section of the book. For this
purpose, not only the final state of the project but each commit was
carefully written with readability in mind. Readers should be able to learn
how a C language feature can be implemented just by reading one or a few
commits of this project. For example, this is how
[while](https://github.com/rui314/chibicc/commit/773115ab2a9c4b96f804311b95b20e9771f0190a),
[[]](https://github.com/rui314/chibicc/commit/75fbd3dd6efde12eac8225d8b5723093836170a5),
[?:](https://github.com/rui314/chibicc/commit/1d0e942fd567a35d296d0f10b7693e98b3dd037c),
and [thread-local
variable](https://github.com/rui314/chibicc/commit/79644e54cc1805e54428cde68b20d6d493b76d34)
are implemented. If you have plenty of spare time, it might be fun to read
it from the [first
commit](https://github.com/rui314/chibicc/commit/0522e2d77e3ab82d3b80a5be8dbbdc8d4180561c).
If you like this project, please consider purchasing a copy of the book
when it becomes available! 😀 I publish the source code here to give people
early access to it, because I was planing to do that anyway with a
permissive open-source license after publishing the book. If I don't charge
for the source code, it doesn't make much sense to me to keep it private. I
hope to publish the book in 2021.
I pronounce chibicc as _chee bee cee cee_. "chibi" means "mini" or
"small" in Japanese. "cc" stands for C compiler.
## Status
Features that are often missing in a small compiler but supported by
chibicc include (but not limited to):
- Preprocessor
- long double (x87 80-bit floting point numbers)
- Bit-field
- alloca()
- Variable-length array
- Thread-local variable
- Atomic variable
- Common symbol
- Designated initializer
- L, u, U and u8 string literals
chibicc does not support digraphs, trigraphs, complex numbers, K&R-style
function prototype, and inline assembly.
chibicc outputs a simple but nice error message when it finds an error in
source code.
There's no optimization pass. chibicc emits terrible code which is probably
twice or more slower than GCC's output. I have a plan to add an
optimization pass once the frontend is done.
## Internals
chibicc consists of the following stages:
- Tokenize: A tokenizer takes a string as an input, breaks it into a list
of tokens and returns them.
- Preprocess: A preprocessor takes as an input a list of tokens and output
a new list of macro-expanded tokens. It interprets preprocessor
directives while expanding macros.
- Parse: A recursive descendent parser constructs abstract syntax trees
from the output of the preprocessor. It also adds a type to each AST
node.
- Codegen: A code generator emits an assembly text for given AST nodes.
## Contributing
When I find a bug in this compiler, I go back to the original commit that
introduced the bug and rewrite the commit history as if there were no such
bug from the beginning. This is an unusual way of fixing bugs, but as a a
part of a book, it is important to keep every commit bug-free.
Thus, I do not take pull requests in this repo. You can send me a pull
request if you find a bug, but it is very likely that I will read your
patch and then apply that to my previous commits by rewriting history. I'll
credit your name somewhere, but your changes will be rewritten by me before
submitted to this repository.
Also, please assume that I will occasionally force-push my local repository
to this public one to rewrite history. If you clone this project and make
local commits on top of it, your changes will have to be rebased by hand
when I force-push new commits.
## About the Author
I'm Rui Ueyama. I'm the creator of [8cc](https://github.com/rui314/8cc),
which is a hobby C compiler, and also the original creator of the current
version of [LLVM lld](https://lld.llvm.org) linker, which is a
production-quality linker used by various operating systems and large-scale
build systems.
## References
- [tcc](https://bellard.org/tcc/): A small C compiler written by Fabrice
Bellard. I learned a lot from this compiler, but the design of tcc and
chibicc are different. In particular, tcc is a one-pass compiler, while
chibicc is a multi-pass one.
- [lcc](https://github.com/drh/lcc): Another small C compiler. The creators
wrote a [book](https://sites.google.com/site/lccretargetablecompiler/)
about the internals of lcc, which I found a good resource to see how a
compiler is implemented.
- [An Incremental Approach to Compiler
Construction](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf)

751
third_party/chibicc/asm.c vendored Normal file
View file

@ -0,0 +1,751 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "third_party/chibicc/chibicc.h"
#define PRECIOUS 0b1111000000101000 // bx,bp,r12-r15
static const char kGreg[4][16][5] = {
{"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b",
"r11b", "r12b", "r13b", "r14b", "r15b"},
{"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w",
"r11w", "r12w", "r13w", "r14w", "r15w"},
{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d",
"r10d", "r11d", "r12d", "r13d", "r14d", "r15d"},
{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10",
"r11", "r12", "r13", "r14", "r15"},
};
StaticAsm *staticasms;
static void DecodeAsmConstraints(AsmOperand *op) {
int i;
char c;
for (i = 0;;) {
switch ((c = op->str[i++])) {
case '\0':
case ',': // alternative group
return;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': // reference
case '=': // output
case '+': // output and input
op->flow = c;
break;
case 'm': // memory
case 'o': // memory offsetable
op->type |= kAsmMem;
op->regmask |= 0b1111111111111111;
break;
case 'i': // int literal, c/asm constexpr, ld embedding
case 'n': // integer literal or compiler constexpr?
case 's': // integer constexpr but not literal (or known at link time?)
case 'M': // i∊[0,3] for index scaling, e.g. "mov\t(?,?,1<<%0),?"
case 'I': // i∊[0,31] 5 bits for 32-bit shifts
case 'J': // i∊[0,63] 6 bits for 64-bit shifts
case 'N': // i∊[0,255] in/out immediate byte
case 'K': // i∊[-128,127] signed byte integer
case 'Z': // i∊[0,2³²) for zero-extending
case 'L': // i∊{0xFF,0xFFFF,0xFFFFFFFF}
op->type |= kAsmImm;
break;
case 'a': // ax
op->regmask |= 0b0000000000000001;
op->type |= kAsmReg;
break;
case 'c': // cx
op->regmask |= 0b0000000000000010;
op->type |= kAsmReg;
break;
case 'd': // dx
op->regmask |= 0b0000000000000100;
op->type |= kAsmReg;
break;
case 'b': // bx
op->regmask |= 0b0000000000001000;
op->type |= kAsmReg;
break;
case 'S': // si
op->regmask |= 0b0000000001000000;
op->type |= kAsmReg;
break;
case 'D': // di
op->regmask |= 0b0000000010000000;
op->type |= kAsmReg;
break;
case 'r': // general register
op->regmask |= 0b1111111111111111;
op->type |= kAsmReg;
break;
case 'q': // greg lo-byte accessible
op->regmask |= 0b1111111111111111;
op->type |= kAsmReg;
break;
case 'Q': // greg hi-byte accessible
op->regmask |= 0b0000000000001111;
op->type |= kAsmReg;
break;
case 'U': // greg call-clobbered
op->regmask |= 0b0000111111000111;
op->type |= kAsmReg;
break;
case 'R': // greg all models
op->regmask |= 0b0000000011111111;
op->type |= kAsmReg;
break;
case 'l': // index register
op->regmask |= 0b1111111111101111;
op->type |= kAsmReg;
break;
case 'y': // mmx
op->type |= kAsmMmx;
op->regmask |= 0b0000000011111111;
break;
case 'x': // xmm
op->type |= kAsmXmm;
op->regmask |= 0b1111111111111111;
break;
case 'g': // rmi
op->type |= kAsmImm | kAsmMem | kAsmReg;
op->regmask |= 0b1111111111111111;
break;
case 'X': // anything
op->type |= kAsmImm | kAsmMem | kAsmReg | kAsmXmm | kAsmFpu | kAsmRaw;
op->regmask |= 0b1111111111111111;
op->x87mask |= 0b11111111;
break;
case 't': // %st
op->type |= kAsmFpu;
op->x87mask |= 0b00000001;
break;
case 'u': // %st(1)
op->type |= kAsmFpu;
op->x87mask |= 0b00000010;
break;
case 'f': // %st(0..7)
op->type |= kAsmFpu;
op->x87mask |= 0b11111111;
break;
case 'A': // ax+dx
error_tok(op->tok, "ax dx constraint not implemented");
case '@': // flags
if (op->flow != '=' || strlen(op->str + i) < 3 ||
(op->str[i] != 'c' || op->str[i + 1] != 'c')) {
error_tok(op->tok, "invalid flag constraint");
}
if (!is_integer(op->node->ty) || op->node->ty->size != 1) {
error_tok(op->node->tok, "invalid output flag type");
}
op->type = kAsmFlag;
op->predicate = i + 2;
return;
default:
break;
}
}
}
static bool IsLvalue(AsmOperand *op) {
switch (op->node->kind) {
case ND_VAR:
case ND_DEREF:
case ND_MEMBER:
case ND_VLA_PTR:
return true;
default:
return false;
}
}
static bool CanUseReg(Node *n) {
return is_integer(n->ty) || n->ty->kind == TY_PTR;
}
static bool CanUseXmm(Node *n) {
return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE ||
n->ty->kind == TY_PTR ||
(n->ty->kind == TY_ARRAY && n->ty->size == 16);
}
static bool CanUseMmx(Node *n) {
return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE ||
n->ty->kind == TY_PTR || (n->ty->kind == TY_ARRAY && n->ty->size == 8);
}
static int PickAsmReferenceType(AsmOperand *op, AsmOperand *ref) {
switch (ref->type) {
case kAsmImm:
case kAsmMem:
error_tok(op->tok, "bad reference");
case kAsmReg:
if (!CanUseReg(op->node)) {
error_tok(op->tok, "expected integral expression");
}
op->regmask = 0;
return ref->type;
case kAsmXmm:
if (!CanUseXmm(op->node)) {
error_tok(op->tok, "expected xmm expression");
}
return ref->type;
case kAsmFpu:
if (op->node->ty->kind != TY_LDOUBLE) {
error_tok(op->tok, "expected long double expression");
}
op->x87mask = 0;
return ref->type;
default:
UNREACHABLE();
}
}
static int PickAsmOperandType(Asm *a, AsmOperand *op) {
if (op->flow == '=' || op->flow == '+') {
op->type &= ~kAsmImm;
if (!IsLvalue(op)) error_tok(op->tok, "lvalue required");
}
if ((op->type & kAsmImm) && is_const_expr(op->node)) {
op->val = eval2(op->node, &op->label);
return kAsmImm;
}
if ((op->type & kAsmMem) && op->node->ty->kind != TY_VOID) return kAsmMem;
if ((op->type & kAsmFpu) && op->node->ty->kind == TY_LDOUBLE) return kAsmFpu;
if ((op->type & kAsmXmm) && CanUseXmm(op->node)) return kAsmXmm;
if ((op->type & kAsmMmx) && CanUseMmx(op->node)) return kAsmMmx;
if ((op->type & kAsmReg) && CanUseReg(op->node)) return kAsmReg;
if (op->type & kAsmFlag) return kAsmFlag;
if (op->type & kAsmRaw) return kAsmRaw;
error_tok(op->tok, "constraint mismatch");
}
static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) {
int i;
op->tok = tok;
op->str = ConsumeStringLiteral(&tok, tok);
tok = skip(tok, "(");
op->node = expr(&tok, tok);
add_type(op->node);
DecodeAsmConstraints(op);
if (isdigit(op->flow)) {
if ((i = op->flow - '0') >= a->n) error_tok(op->tok, "bad reference");
op->type = PickAsmReferenceType(op, a->ops + i);
} else {
op->type = PickAsmOperandType(a, op);
}
return skip(tok, ")");
}
static Token *ParseAsmOperands(Asm *a, Token *tok) {
if (EQUAL(tok, ":")) return tok;
for (;;) {
if (a->n == ARRAYLEN(a->ops)) {
error_tok(tok, "too many asm operands");
}
tok = ParseAsmOperand(a, &a->ops[a->n], tok);
++a->n;
if (!EQUAL(tok, ",")) break;
tok = skip(tok, ",");
}
return tok;
}
static void CouldNotAllocateRegister(AsmOperand *op) {
error_tok(op->tok, "could not allocate register");
}
static void PickAsmRegisters(Asm *a) {
int i, j, m, regset, xmmset, x87sts;
regset = 0b0000111111000111; // exclude bx,sp,bp,r12-r15
xmmset = 0b1111111111111111;
x87sts = 0b0000000011111111;
regset ^= regset & a->regclob; // don't allocate from clobber list
xmmset ^= xmmset & a->xmmclob;
x87sts ^= x87sts & a->x87clob;
for (j = 1; j <= 16; ++j) { // iterate from most to least restrictive
for (i = 0; i < a->n; ++i) {
switch (a->ops[i].type) {
case kAsmMem:
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)));
a->ops[i].regmask = 0;
break;
case kAsmXmm:
if (!(m = a->ops[i].regmask)) break;
if (!(m &= xmmset)) CouldNotAllocateRegister(&a->ops[i]);
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]);
x87sts &= ~(1 << (a->ops[i].reg = bsf(m)));
a->ops[i].x87mask = 0;
break;
default:
a->ops[i].regmask = 0;
a->ops[i].x87mask = 0;
break;
}
}
}
for (i = 0; i < a->n; ++i) {
assert(!a->ops[i].regmask);
assert(!a->ops[i].x87mask);
}
}
static void MarkUsedAsmOperands(Asm *a) {
char c, *p;
if (!a->isgnu) return;
for (p = a->str; (c = *p++);) {
if (c == '%') {
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
if (c == '%') continue;
if (!isdigit(c)) {
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
if (!isdigit(c)) {
error_tok(a->tok, "bad asm specifier");
}
}
a->ops[c - '0'].isused = true;
}
}
}
static int GetIndexOfRegisterName(const char *s) {
int i, j;
for (i = 0; i < 16; ++i) {
for (j = 0; j < 4; ++j) {
if (!strcmp(s, kGreg[j][i])) {
return i;
}
}
}
return -1;
}
static Token *ParseAsmClobbers(Asm *a, Token *tok) {
int i;
char *s;
Token *stok;
for (;;) {
stok = tok;
s = ConsumeStringLiteral(&tok, tok);
if (*s == '%') ++s;
if (!strcmp(s, "cc")) {
a->flagclob = true;
} else if ((i = GetIndexOfRegisterName(s)) != -1) {
a->regclob |= 1 << i;
} else if (startswith(s, "xmm") && isdigit(s[3]) &&
(!s[4] || isdigit(s[4]))) {
i = s[3] - '0';
if (s[4]) {
i *= 10;
i += s[4] - '0';
}
i &= 15;
a->xmmclob |= 1 << i;
} else if (!strcmp(s, "st")) {
a->x87clob |= 1;
} else if (startswith(s, "st(") && isdigit(s[3]) && s[4] == ')') {
i = s[3] - '0';
i &= 7;
a->x87clob |= 1 << i;
} else {
error_tok(stok, "unknown clobber register");
}
if (!EQUAL(tok, ",")) break;
tok = skip(tok, ",");
}
return tok;
}
// parses ansi c11 asm statement officially defined as follows
//
// asm-stmt = "asm" ("volatile" | "inline")* "(" string-literal ")"
//
// gnu c defines a notation for inputs, outputs, and clobbers, e.g.
//
// asm("foo %1,%0"
// : "=r"(x)
// : "r"(x)
// : "cc");
//
Asm *asm_stmt(Token **rest, Token *tok) {
Asm *a = calloc(1, sizeof(Asm));
tok = tok->next;
while (EQUAL(tok, "volatile") || EQUAL(tok, "inline")) tok = tok->next;
tok = skip(tok, "(");
a->tok = tok;
a->str = ConsumeStringLiteral(&tok, tok);
if (!EQUAL(tok, ")")) {
a->isgnu = true;
tok = skip(tok, ":");
tok = ParseAsmOperands(a, tok);
if (!EQUAL(tok, ")")) {
tok = skip(tok, ":");
tok = ParseAsmOperands(a, tok);
if (!EQUAL(tok, ")")) {
tok = skip(tok, ":");
tok = ParseAsmClobbers(a, tok);
}
}
}
PickAsmRegisters(a);
MarkUsedAsmOperands(a);
*rest = skip(tok, ")");
return a;
}
static void PrintAsmConstant(AsmOperand *op) {
if (op->label) {
fprintf(output_stream, "%s%+ld", *op->label, op->val);
} else {
fprintf(output_stream, "%ld", op->val);
}
}
static void EmitAsmSpecifier(AsmOperand *op, int q, int z) {
if (!q) {
switch (op->type) {
case kAsmImm:
fputc('$', output_stream);
PrintAsmConstant(op);
break;
case kAsmMem:
fprintf(output_stream, "(%%%s)", kGreg[3][op->reg]);
break;
case kAsmReg:
fprintf(output_stream, "%%%s", kGreg[z][op->reg]);
break;
case kAsmXmm:
fprintf(output_stream, "%%xmm%d", op->reg);
break;
case kAsmFpu:
fprintf(output_stream, "%%st(%d)", op->reg);
break;
case kAsmRaw:
fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc);
break;
default:
UNREACHABLE();
}
} else {
switch (q) {
case 'h': // hi byte
fprintf(output_stream, "%%%ch", "acdb"[op->reg]);
break;
case 'b': // lo byte
fprintf(output_stream, "%%%s", kGreg[0][op->reg]);
break;
case 'w': // word
fprintf(output_stream, "%%%s", kGreg[1][op->reg]);
break;
case 'k': // dword
fprintf(output_stream, "%%%s", kGreg[2][op->reg]);
break;
case 'q': // qword
fprintf(output_stream, "%%%s", kGreg[3][op->reg]);
break;
case 'z': // print suffix
fprintf(output_stream, "%c", "bwlq"[z]);
break;
case 'p': // print raw
fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc);
break;
case 'a': // print address
PrintAsmConstant(op);
break;
case 'c': // print constant w/o punctuation
PrintAsmConstant(op);
break;
case 'P': // print w/ @plt
PrintAsmConstant(op);
fprintf(output_stream, "@plt");
break;
case 'l': // print label w/o punctuation
if (!op->label) {
error_tok(op->tok, "qualifier expected label");
}
fprintf(output_stream, "%s", *op->label);
break;
case 'V': // print register w/o punctuation
if (op->type != kAsmReg) {
error_tok(op->tok, "qualifier expected register");
}
fprintf(output_stream, "%s", kGreg[z][op->reg]);
break;
default:
error_tok(op->tok, "bad asm qualifier %%%`'c", q);
}
}
}
static char *HandleAsmSpecifier(Asm *a, char *p) {
int c, i, q, z;
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
if (c == '%') {
fputc('%', output_stream);
return p;
}
if (c == '=') {
fprintf(output_stream, "%d", count());
return p;
}
if (isdigit(c)) {
q = '\0';
} else {
q = c;
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
if (!isdigit(c)) {
error_tok(a->tok, "bad asm specifier at offset %d", p - a->str);
}
}
if ((i = c - '0') >= a->n) {
error_tok(a->tok, "bad asm reference at offset %d", p - a->str);
}
z = bsr(a->ops[i].node->ty->size);
if (z > 3 && a->ops[i].type == kAsmReg) {
error_tok(a->tok, "bad asm op size");
}
EmitAsmSpecifier(&a->ops[i], q, z);
return p;
}
static void EmitAsmText(Asm *a) {
char c, *p;
if (a->isgnu) {
flushln();
fprintf(output_stream, "\t");
for (p = a->str;;) {
switch ((c = *p++)) {
case '\0':
fputc('\n', output_stream);
return;
case '%':
p = HandleAsmSpecifier(a, p);
break;
default:
fputc(c, output_stream);
break;
}
}
} else {
println("\t%s", a->str);
}
}
static void PushAsmInput(AsmOperand *op) {
gen_expr(op->node);
push();
}
static void PushAsmInputs(Asm *a) {
int i;
for (i = 0; i < a->n; ++i) {
if (a->ops[i].flow == '=') continue;
switch (a->ops[i].type) {
case kAsmReg:
PushAsmInput(&a->ops[i]);
break;
case kAsmMem:
if (a->ops[i].isused) {
PushAsmInput(&a->ops[i]);
}
break;
case kAsmXmm:
gen_expr(a->ops[i].node);
println("\tsub\t$16,%%rsp");
switch (a->ops[i].node->ty->kind) {
case TY_FLOAT:
case TY_DOUBLE:
println("\tmovdqu\t%%xmm0,(%%rsp)");
break;
default:
println("\tmovdqu\t(%%rax),%%xmm0");
println("\tmovdqu\t%%xmm0,(%%rsp)");
break;
}
break;
case kAsmMmx:
gen_expr(a->ops[i].node);
println("\tsub\t$8,%%rsp");
switch (a->ops[i].node->ty->kind) {
case TY_FLOAT:
case TY_DOUBLE:
println("\tmovq\t%%mm0,(%%rsp)");
break;
default:
println("\tmovq\t(%%rax),%%mm0");
println("\tmovq\t%%mm0,(%%rsp)");
break;
}
break;
case kAsmFpu: /* TODO: How does this work in non-simple case? */
gen_expr(a->ops[i].node);
println("\tsub\t$16,%%rsp");
println("\tfstpt\t(%%rsp)");
break;
default:
break;
}
}
}
static void PopAsmInput(Asm *a, AsmOperand *op) {
if (isdigit(op->flow)) {
popreg(kGreg[3][a->ops[op->flow - '0'].reg]);
} else {
popreg(kGreg[3][op->reg]);
}
}
static void PopAsmInputs(Asm *a) {
int i;
for (i = a->n; i--;) {
if (a->ops[i].flow == '=') continue;
switch (a->ops[i].type) {
case kAsmReg:
PopAsmInput(a, &a->ops[i]);
break;
case kAsmMem:
if (a->ops[i].isused) {
PopAsmInput(a, &a->ops[i]);
}
break;
case kAsmXmm:
println("\tmovdqu\t(%%rsp),%%xmm%d", a->ops[i].reg);
println("\tadd\t$16,%%rsp");
break;
case kAsmMmx:
println("\tmovq\t(%%rsp),%%mm%d", a->ops[i].reg);
println("\tadd\t$8,%%rsp");
break;
case kAsmFpu: /* TODO: How does this work in non-simple case? */
println("\tfldt\t(%%rsp)");
println("\tadd\t$16,%%rsp");
break;
default:
break;
}
}
}
static void StoreAsmOutputs(Asm *a) {
int i, z, x0, x1;
for (i = 0; i < a->n; ++i) {
if (a->ops[i].flow == '=' || a->ops[i].flow == '+') {
switch (a->ops[i].type) {
case kAsmFlag:
gen_addr(a->ops[i].node);
println("\tset%s\t(%%rax)", a->ops[i].str + a->ops[i].predicate);
break;
case kAsmReg:
if (a->ops[i].reg) {
gen_addr(a->ops[i].node);
z = bsr(a->ops[i].node->ty->size);
if (z > 3) error_tok(a->tok, "bad asm out size");
println("\tmov\t%%%s,(%%rax)", kGreg[z][a->ops[i].reg]);
} else {
println("\tpush\t%%rbx");
push();
pop("%rbx");
gen_addr(a->ops[i].node);
println("\tmov\t%%rbx,(%%rax)");
println("\tpop\t%%rbx");
}
break;
case kAsmXmm:
gen_addr(a->ops[i].node);
switch (a->ops[i].node->ty->kind) {
case TY_FLOAT:
println("\tmovss\t%%xmm%d,(%%rax)", a->ops[i].reg);
break;
case TY_DOUBLE:
println("\tmovsd\t%%xmm%d,(%%rax)", a->ops[i].reg);
break;
default:
println("\tmovdqu\t%%xmm%d,(%%rax)", a->ops[i].reg);
break;
}
break;
case kAsmMmx:
gen_addr(a->ops[i].node);
switch (a->ops[i].node->ty->kind) {
case TY_FLOAT:
println("\tmovss\t%%mm%d,(%%rax)", a->ops[i].reg);
break;
case TY_DOUBLE:
println("\tmovsd\t%%mm%d,(%%rax)", a->ops[i].reg);
break;
default:
println("\tmovq\t%%mm%d,(%%rax)", a->ops[i].reg);
break;
}
break;
case kAsmFpu: /* TODO: How does this work in non-simple case? */
gen_addr(a->ops[i].node);
println("\tfstpt\t(%%rax)");
break;
default:
break;
}
}
}
}
static void PushClobbers(Asm *a) {
int i, regs = a->regclob & PRECIOUS;
while (regs) {
i = bsf(regs);
pushreg(kGreg[3][i]);
regs &= ~(1 << i);
}
}
static void PopClobbers(Asm *a) {
int i, regs = a->regclob & PRECIOUS;
while (regs) {
i = bsr(regs);
popreg(kGreg[3][i]);
regs &= ~(1 << i);
}
}
// generates shocking horrible code for parsed asm statement
void gen_asm(Asm *a) {
PushAsmInputs(a);
print_loc(a->tok->file->file_no, a->tok->line_no);
PopAsmInputs(a);
PushClobbers(a);
EmitAsmText(a);
StoreAsmOutputs(a);
PopClobbers(a);
}

179
third_party/chibicc/cast.c vendored Normal file
View file

@ -0,0 +1,179 @@
#include "third_party/chibicc/chibicc.h"
#define REDZONE(X) \
"sub\t$16,%rsp\n" \
"\t" X "\n" \
"\tadd\t$16,%rsp"
#define PUSHPOPRAX(X) \
"push\t%rax\n" \
"\t" X "\n" \
"\tpop\t%rax"
#ifdef __SSE3__
#define FIST(X) REDZONE("fistt" X)
#else
#define FIST(X) \
REDZONE("fnstcw\t8(%rsp)\n" \
"\tmovzwl\t8(%rsp),%eax\n" \
"\tor\t$12,%ah\n" \
"\tmov\t%ax,10(%rsp)\n" \
"\tfldcw\t10(%rsp)\n" \
"\tfist" X "\n" \
"\tfldcw\t8(%rsp)")
#endif
#define u64f64 \
"test\t%rax,%rax\n" \
"\tjs\t1f\n" \
"\tpxor\t%xmm0,%xmm0\n" \
"\tcvtsi2sd %rax,%xmm0\n" \
"\tjmp\t2f\n" \
"1:\n" \
"\tmov\t%rax,%rdi\n" \
"\tand\t$1,%eax\n" \
"\tpxor\t%xmm0,%xmm0\n" \
"\tshr\t%rdi\n" \
"\tor\t%rax,%rdi\n" \
"\tcvtsi2sd %rdi,%xmm0\n" \
"\taddsd\t%xmm0,%xmm0\n" \
"2:"
#define u64f80 \
PUSHPOPRAX("fildq\t(%rsp)\n" \
"\ttest\t%rax,%rax\n" \
"\tjns\t1f\n" \
"\tmov\t$0x5f800000,(%rsp)\n" \
"\tfadds\t(%rsp)\n" \
"1:")
#define i32i8 "movsbl\t%al,%eax"
#define i32u8 "movzbl\t%al,%eax"
#define i32i16 "cwtl"
#define i32u16 "movzwl\t%ax,%eax"
#define i32f32 "cvtsi2ssl %eax,%xmm0"
#define i32i64 "cltq"
#define i32f64 "cvtsi2sdl %eax,%xmm0"
#define u32i64 "mov\t%eax,%eax"
#define i64f32 "cvtsi2ssq %rax,%xmm0"
#define i64f64 "cvtsi2sdq %rax,%xmm0"
#define f32i32 "cvttss2sil %xmm0,%eax"
#define f32u32 "cvttss2siq %xmm0,%rax"
#define f32i64 "cvttss2siq %xmm0,%rax"
#define f32u64 "cvttss2siq %xmm0,%rax"
#define f32f64 "cvtss2sd %xmm0,%xmm0"
#define f64i32 "cvttsd2sil %xmm0,%eax"
#define f64u32 "cvttsd2siq %xmm0,%rax"
#define f64i64 "cvttsd2siq %xmm0,%rax"
#define f64u64 "cvttsd2siq %xmm0,%rax"
#define f64f32 "cvtsd2ss %xmm0,%xmm0"
#define u64f32 "cvtsi2ssq %rax,%xmm0"
#define f32i8 "cvttss2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
#define f32u8 "cvttss2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
#define f32i16 "cvttss2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
#define f32u16 "cvttss2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
#define f64i8 "cvttsd2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
#define f64u8 "cvttsd2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
#define f64i16 "cvttsd2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
#define f64u16 "cvttsd2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
#define f64f80 REDZONE("movsd\t%xmm0,(%rsp)\n\tfldl\t(%rsp)")
#define f80i8 FIST("ps\t(%rsp)\n\tmovsbl\t(%rsp),%eax")
#define f80u8 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
#define f80i16 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
#define f80u16 FIST("pl\t(%rsp)\n\tmovswl\t(%rsp),%eax")
#define f80i32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
#define f80u32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
#define f80i64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
#define f80u64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
#define f80f32 REDZONE("fstps\t(%rsp)\n\tmovss\t(%rsp),%xmm0")
#define f80f64 REDZONE("fstpl\t(%rsp)\n\tmovsd\t(%rsp),%xmm0")
#define i32f80 PUSHPOPRAX("fildl\t(%rsp)")
#define u32f32 "mov\t%eax,%eax\n\tcvtsi2ssq %rax,%xmm0"
#define u32f64 "mov\t%eax,%eax\n\tcvtsi2sdq %rax,%xmm0"
#define u32f80 "mov\t%eax,%eax\n\tpush %rax\n\tfildll\t(%rsp)\n\tpop\t%rax"
#define i64f80 PUSHPOPRAX("fildll\t(%rsp)")
#define f32f80 REDZONE("movss\t%xmm0,(%rsp)\n\tflds\t(%rsp)")
#define i8i128 "movsbq\t%al,%rax\n\tcqto"
#define i16i128 "movswq\t%ax,%rax\n\tcqto"
#define i32i128 "cltq\n\tcqto"
#define i64i128 "cqto"
#define u8i128 "movzbq\t%al,%rax\n\txor\t%edx,%edx"
#define u16i128 "movzwq\t%ax,%rax\n\txor\t%edx,%edx"
#define u32i128 "cltq\n\txor\t%edx,%edx"
#define u64i128 "xor\t%edx,%edx"
#define i128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattisf"
#define i128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattidf"
#define i128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattixf"
#define u128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntisf"
#define u128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntidf"
#define u128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntixf"
#define f32i128 "call\t__fixsfti"
#define f64i128 "call\t__fixdfti"
#define f80i128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixxfti")
#define f32u128 "call\t__fixunssfti"
#define f64u128 "call\t__fixunsdfti"
#define f80u128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixunsxfti")
enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80, I128, U128 };
static const char *const cast_table[13][13] = /* clang-format off */ {
// i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80 i128 u128
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i8
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i16
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80, i64i128, i64i128}, // i64
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u8
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u16
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80, u32i128, i32i128}, // u32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80, u64i128, u64i128}, // u64
{f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80, f32i128, f32u128}, // f32
{f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80, f64i128, f64u128}, // f64
{f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL, f80i128, f80u128}, // f80
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i128f32, i128f64, i128f80, NULL, NULL }, // i128
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u128f32, u128f64, u128f80, NULL, NULL }, // u128
} /* clang-format on */;
static int getTypeId(Type *ty) {
switch (ty->kind) {
case TY_CHAR:
return ty->is_unsigned ? U8 : I8;
case TY_SHORT:
return ty->is_unsigned ? U16 : I16;
case TY_INT:
return ty->is_unsigned ? U32 : I32;
case TY_LONG:
return ty->is_unsigned ? U64 : I64;
case TY_INT128:
return ty->is_unsigned ? U128 : I128;
case TY_FLOAT:
return F32;
case TY_DOUBLE:
return F64;
case TY_LDOUBLE:
return F80;
}
return U64;
}
void gen_cast(Type *from, Type *to) {
bool skew;
if (to->kind == TY_VOID) return;
if (to->kind == TY_BOOL) {
cmp_zero(from);
println("\tsetne\t%%al");
println("\tmovzbl\t%%al,%%eax");
return;
}
int t1 = getTypeId(from);
int t2 = getTypeId(to);
if (cast_table[t1][t2]) {
if ((skew = (depth & 1) && strstr(cast_table[t1][t2], "call"))) {
println("\tsub\t$8,%%rsp");
depth++;
}
println("\t%s", cast_table[t1][t2]);
if (skew) {
println("\tadd\t$8,%%rsp");
depth--;
}
}
}

View file

@ -1,20 +1,30 @@
#include "third_party/chibicc/chibicc.h"
asm(".ident\t\"\\n\\n\
chibicc (MIT/ISC License)\\n\
Copyright 2019 Rui Ueyama\\n\
Copyright 2020 Justine Alexandra Roberts Tunney\"");
asm(".include \"libc/disclaimer.inc\"");
typedef enum {
FILE_NONE,
FILE_C,
FILE_ASM,
FILE_ASM_CPP,
FILE_OBJ,
FILE_AR,
FILE_DSO,
} FileType;
StringArray include_paths;
bool opt_fcommon = true;
bool opt_fpic;
bool opt_verbose;
bool opt_mpopcnt;
bool opt_pg;
bool opt_mfentry;
bool opt_mnop_mcount;
bool opt_mrecord_mcount;
static FileType opt_x;
static StringArray opt_include;
static bool opt_E;
static bool opt_M;
static bool opt_MD;
@ -25,19 +35,20 @@ static bool opt_c;
static bool opt_cc1;
static bool opt_hash_hash_hash;
static bool opt_static;
static bool opt_shared;
static char *opt_MF;
static char *opt_MT;
static char *opt_o;
static FileType opt_x;
static StringArray opt_include;
StringArray include_paths;
static StringArray ld_extra_args;
static StringArray as_extra_args;
static StringArray std_include_paths;
char *base_file;
static char *output_file;
static StringArray input_paths;
static char **tmpfiles;
static void usage(int status) {
@ -46,48 +57,49 @@ static void usage(int status) {
}
static bool take_arg(char *arg) {
char *x[] = {
"-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker",
};
for (int i = 0; i < sizeof(x) / sizeof(*x); i++)
if (!strcmp(arg, x[i])) return true;
char *x[] = {"-o", "-I", "-idirafter", "-include",
"-x", "-MF", "-MT", "-Xlinker"};
for (int i = 0; i < sizeof(x) / sizeof(*x); i++) {
if (!strcmp(arg, x[i])) {
return true;
}
}
return false;
}
static void add_default_include_paths(char *argv0) {
// We expect that chibicc-specific include files are installed
// to ./include relative to argv[0].
char *buf = calloc(1, strlen(argv0) + 10);
sprintf(buf, "%s/include", dirname(strdup(argv0)));
strarray_push(&include_paths, buf);
/* char *buf = calloc(1, strlen(argv0) + 10); */
/* sprintf(buf, "%s/include", dirname(strdup(argv0))); */
/* strarray_push(&include_paths, buf); */
// Add standard include paths.
strarray_push(&include_paths, ".");
/* strarray_push(&include_paths, "."); */
// Keep a copy of the standard include paths for -MMD option.
for (int i = 0; i < include_paths.len; i++)
for (int i = 0; i < include_paths.len; i++) {
strarray_push(&std_include_paths, include_paths.data[i]);
}
}
static void define(char *str) {
char *eq = strchr(str, '=');
if (eq)
if (eq) {
define_macro(strndup(str, eq - str), eq + 1);
else
} else {
define_macro(str, "1");
}
}
static FileType parse_opt_x(char *s) {
if (!strcmp(s, "c")) return FILE_C;
if (!strcmp(s, "assembler")) return FILE_ASM;
if (!strcmp(s, "assembler-with-cpp")) return FILE_ASM_CPP;
if (!strcmp(s, "none")) return FILE_NONE;
error("<command line>: unknown argument for -x: %s", s);
}
static char *quote_makefile(char *s) {
char *buf = calloc(1, strlen(s) * 2 + 1);
for (int i = 0, j = 0; s[i]; i++) {
switch (s[i]) {
case '$':
@ -112,255 +124,254 @@ static char *quote_makefile(char *s) {
return buf;
}
static void PrintMemoryUsage(void) {
struct mallinfo mi;
mi = mallinfo();
fprintf(stderr, "allocated %,ld bytes of memory\n", mi.arena);
}
static void parse_args(int argc, char **argv) {
// Make sure that all command line options that take an argument
// have an argument.
for (int i = 1; i < argc; i++)
if (take_arg(argv[i]))
if (!argv[++i]) usage(1);
StringArray idirafter = {};
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-###")) {
opt_hash_hash_hash = true;
continue;
}
if (!strcmp(argv[i], "-cc1")) {
opt_cc1 = true;
continue;
}
if (!strcmp(argv[i], "--help")) usage(0);
if (!strcmp(argv[i], "-v")) {
opt_verbose = true;
atexit(PrintMemoryUsage);
continue;
}
if (!strcmp(argv[i], "-o")) {
opt_o = argv[++i];
continue;
}
if (!strncmp(argv[i], "-o", 2)) {
opt_o = argv[i] + 2;
continue;
}
if (!strcmp(argv[i], "-S")) {
opt_S = true;
continue;
}
if (!strcmp(argv[i], "-fcommon")) {
opt_fcommon = true;
continue;
}
if (!strcmp(argv[i], "-fno-common")) {
opt_fcommon = false;
continue;
}
if (!strcmp(argv[i], "-c")) {
opt_c = true;
continue;
}
if (!strcmp(argv[i], "-E")) {
opt_E = true;
continue;
}
if (!strncmp(argv[i], "-I", 2)) {
strarray_push(&include_paths, argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-D")) {
define(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-D", 2)) {
define(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-U")) {
undef_macro(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-U", 2)) {
undef_macro(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-include")) {
strarray_push(&opt_include, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-x")) {
opt_x = parse_opt_x(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-x", 2)) {
opt_x = parse_opt_x(argv[i] + 2);
continue;
}
if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
strarray_push(&input_paths, argv[i]);
continue;
}
if (!strcmp(argv[i], "-Xassembler")) {
strarray_push(&as_extra_args, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-Xlinker")) {
strarray_push(&ld_extra_args, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-s")) {
strarray_push(&ld_extra_args, "-s");
continue;
}
if (!strcmp(argv[i], "-M")) {
opt_M = true;
continue;
}
if (!strcmp(argv[i], "-MF")) {
opt_MF = argv[++i];
continue;
}
if (!strcmp(argv[i], "-MP")) {
opt_MP = true;
continue;
}
if (!strcmp(argv[i], "-MT")) {
if (opt_MT == NULL)
opt_MT = argv[++i];
else
opt_MT = format("%s %s", opt_MT, argv[++i]);
opt_MT = xasprintf("%s %s", opt_MT, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-MD")) {
opt_MD = true;
continue;
}
if (!strcmp(argv[i], "-MQ")) {
if (opt_MT == NULL)
opt_MT = quote_makefile(argv[++i]);
else
opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i]));
opt_MT = xasprintf("%s %s", opt_MT, quote_makefile(argv[++i]));
continue;
}
if (!strcmp(argv[i], "-MMD")) {
opt_MD = opt_MMD = true;
continue;
}
if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) {
if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") ||
!strcmp(argv[i], "-fPIC")) {
opt_fpic = true;
continue;
}
if (!strcmp(argv[i], "-pg")) {
opt_pg = true;
continue;
}
if (!strcmp(argv[i], "-mfentry")) {
opt_mfentry = true;
continue;
}
if (!strcmp(argv[i], "-mrecord-mcount")) {
opt_mrecord_mcount = true;
continue;
}
if (!strcmp(argv[i], "-mnop-mcount")) {
opt_mnop_mcount = true;
continue;
}
if (!strcmp(argv[i], "-mpopcnt")) {
opt_mpopcnt = true;
continue;
}
if (!strcmp(argv[i], "-cc1-input")) {
base_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-cc1-output")) {
output_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-idirafter")) {
strarray_push(&idirafter, argv[i++]);
continue;
}
if (!strcmp(argv[i], "-static")) {
opt_static = true;
strarray_push(&ld_extra_args, "-static");
continue;
}
if (!strcmp(argv[i], "-shared")) {
opt_shared = true;
strarray_push(&ld_extra_args, "-shared");
continue;
fprintf(stderr, "error: -shared not supported\n");
exit(1);
}
if (!strcmp(argv[i], "-L")) {
strarray_push(&ld_extra_args, "-L");
strarray_push(&ld_extra_args, argv[++i]);
continue;
}
if (!strncmp(argv[i], "-L", 2)) {
strarray_push(&ld_extra_args, "-L");
strarray_push(&ld_extra_args, argv[i] + 2);
continue;
}
#if 0
if (!strcmp(argv[i], "-hashmap-test")) {
hashmap_test();
exit(0);
}
#endif
// These options are ignored for now.
if (!strncmp(argv[i], "-O", 2) || !strncmp(argv[i], "-W", 2) ||
!strncmp(argv[i], "-g", 2) || !strncmp(argv[i], "-std=", 5) ||
!strcmp(argv[i], "-ffreestanding") ||
if (startswith(argv[i], "-O") || startswith(argv[i], "-W") ||
startswith(argv[i], "-g") || startswith(argv[i], "-std=") ||
startswith(argv[i], "-fno-") || startswith(argv[i], "-mno-") ||
startswith(argv[i], "-fsanitize") ||
startswith(argv[i], "-fdebug-prefix-map") ||
!strcmp(argv[i], "-fwrapv") || !strcmp(argv[i], "-nostdlib") ||
!strcmp(argv[i], "-nostdinc") || !strcmp(argv[i], "-ffreestanding") ||
!strcmp(argv[i], "-fstrict-aliasing") ||
!strcmp(argv[i], "-fstrict-overflow") ||
!strcmp(argv[i], "-frecord-gcc-switches") ||
!strcmp(argv[i], "-fsignaling-nans") ||
!strcmp(argv[i], "-frounding-math") ||
!strcmp(argv[i], "-fcx-limited-range") ||
!strcmp(argv[i], "-fmodulo-sched") ||
!strcmp(argv[i], "-fmerge-constants") ||
!strcmp(argv[i], "-fmerge-all-constants") ||
!strcmp(argv[i], "-fno-builtin") ||
!strcmp(argv[i], "-fno-omit-frame-pointer") ||
!strcmp(argv[i], "-fno-stack-protector") ||
!strcmp(argv[i], "-fno-strict-aliasing") || !strcmp(argv[i], "-m64") ||
!strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w"))
!strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w")) {
continue;
}
if (argv[i][0] == '-' && argv[i][1] != '\0')
error("unknown argument: %s", argv[i]);
strarray_push(&input_paths, argv[i]);
}
for (int i = 0; i < idirafter.len; i++)
strarray_push(&include_paths, idirafter.data[i]);
if (input_paths.len == 0) error("no input files");
// -E implies that the input is the C macro language.
if (opt_E) opt_x = FILE_C;
}
static FILE *open_file(char *path) {
if (!path || strcmp(path, "-") == 0) return stdout;
FILE *out = fopen(path, "w");
if (!out) error("cannot open output file: %s: %s", path, strerror(errno));
return out;
}
static bool ends_with(char *p, char *q) {
int len1 = strlen(p);
int len2 = strlen(q);
return (len1 >= len2) && !strcmp(p + len1 - len2, q);
}
// Replace file extension
static char *replace_extn(char *tmpl, char *extn) {
char *filename = basename(strdup(tmpl));
int len1 = strlen(filename);
int len2 = strlen(extn);
char *buf = calloc(1, len1 + len2 + 2);
char *dot = strrchr(filename, '.');
if (dot) *dot = '\0';
sprintf(buf, "%s%s", filename, extn);
@ -368,25 +379,23 @@ static char *replace_extn(char *tmpl, char *extn) {
}
static void cleanup(void) {
if (tmpfiles)
for (int i = 0; tmpfiles[i]; i++) unlink(tmpfiles[i]);
if (tmpfiles) {
for (int i = 0; tmpfiles[i]; i++) {
unlink(tmpfiles[i]);
}
}
}
static char *create_tmpfile(void) {
char tmpl[] = "/tmp/chibicc-XXXXXX";
char *path = calloc(1, sizeof(tmpl));
memcpy(path, tmpl, sizeof(tmpl));
char *path = xstrcat(kTmpPath, "chibicc-XXXXXX");
int fd = mkstemp(path);
if (fd == -1) error("mkstemp failed: %s", strerror(errno));
close(fd);
static int len = 2;
tmpfiles = realloc(tmpfiles, sizeof(char *) * len);
tmpfiles[len - 2] = path;
tmpfiles[len - 1] = NULL;
len++;
return path;
}
@ -397,43 +406,41 @@ static void run_subprocess(char **argv) {
for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]);
fprintf(stderr, "\n");
}
if (fork() == 0) {
// Child process. Run a new command.
execvp(argv[0], argv);
fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno));
_exit(1);
}
// Wait for the child process to finish.
int status;
while (wait(&status) > 0)
;
if (status != 0) exit(1);
for (;;) {
if (wait(&status) <= 0) {
break;
}
}
if (status != 0) {
exit(1);
}
}
static void run_cc1(int argc, char **argv, char *input, char *output) {
char **args = calloc(argc + 10, sizeof(char *));
memcpy(args, argv, argc * sizeof(char *));
args[argc++] = "-cc1";
if (input) {
args[argc++] = "-cc1-input";
args[argc++] = input;
}
if (output) {
args[argc++] = "-cc1-output";
args[argc++] = output;
}
run_subprocess(args);
}
// Print tokens to stdout. Used for -E.
static void print_tokens(Token *tok) {
FILE *out = open_file(opt_o ? opt_o : "-");
int line = 1;
for (; tok->kind != TK_EOF; tok = tok->next) {
if (line > 1 && tok->at_bol) fprintf(out, "\n");
@ -458,30 +465,26 @@ static bool in_std_include_path(char *path) {
// used to automate file dependency management.
static void print_dependencies(void) {
char *path;
if (opt_MF)
if (opt_MF) {
path = opt_MF;
else if (opt_MD)
} else if (opt_MD) {
path = replace_extn(opt_o ? opt_o : base_file, ".d");
else if (opt_o)
} else if (opt_o) {
path = opt_o;
else
} else {
path = "-";
}
FILE *out = open_file(path);
if (opt_MT)
fprintf(out, "%s:", opt_MT);
else
fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o")));
File **files = get_input_files();
for (int i = 0; files[i]; i++) {
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
fprintf(out, " \\\n %s", files[i]->name);
}
fprintf(out, "\n\n");
if (opt_MP) {
for (int i = 1; files[i]; i++) {
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
@ -498,51 +501,52 @@ static Token *must_tokenize_file(char *path) {
static Token *append_tokens(Token *tok1, Token *tok2) {
if (!tok1 || tok1->kind == TK_EOF) return tok2;
Token *t = tok1;
while (t->next->kind != TK_EOF) t = t->next;
t->next = tok2;
return tok1;
}
static FileType get_file_type(char *filename) {
if (opt_x != FILE_NONE) return opt_x;
if (endswith(filename, ".a")) return FILE_AR;
if (endswith(filename, ".o")) return FILE_OBJ;
if (endswith(filename, ".c")) return FILE_C;
if (endswith(filename, ".s")) return FILE_ASM;
if (endswith(filename, ".S")) return FILE_ASM_CPP;
error("<command line>: unknown file extension: %s", filename);
}
static void cc1(void) {
Token *tok = NULL;
// Process -include option
for (int i = 0; i < opt_include.len; i++) {
char *incl = opt_include.data[i];
char *path;
if (file_exists(incl)) {
if (fileexists(incl)) {
path = incl;
} else {
path = search_include_paths(incl);
if (!path) error("-include: %s: %s", incl, strerror(errno));
}
Token *tok2 = must_tokenize_file(path);
tok = append_tokens(tok, tok2);
}
// Tokenize and parse.
Token *tok2 = must_tokenize_file(base_file);
tok = append_tokens(tok, tok2);
tok = preprocess(tok);
// If -M or -MD are given, print file dependencies.
if (opt_M || opt_MD) {
print_dependencies();
if (opt_M) return;
}
// If -E is given, print out preprocessed C code as a result.
if (opt_E) {
if (opt_E || get_file_type(base_file) == FILE_ASM_CPP) {
print_tokens(tok);
return;
}
Obj *prog = parse(tok);
// Traverse the AST to emit assembly.
FILE *out = open_file(output_file);
codegen(prog, out);
@ -550,108 +554,72 @@ static void cc1(void) {
}
static void assemble(char *input, char *output) {
char *cmd[] = {"as", "-W", "-I.", "-c", input, "-o", output, NULL};
run_subprocess(cmd);
char *as = getenv("AS");
if (!as || !*as) as = "as";
StringArray arr = {};
strarray_push(&arr, as);
strarray_push(&arr, "-W");
strarray_push(&arr, "-I.");
strarray_push(&arr, "-c");
for (int i = 0; i < as_extra_args.len; i++) {
strarray_push(&arr, as_extra_args.data[i]);
}
strarray_push(&arr, input);
strarray_push(&arr, "-o");
strarray_push(&arr, output);
strarray_push(&arr, NULL);
run_subprocess(arr.data);
}
static void run_linker(StringArray *inputs, char *output) {
char *ld = getenv("LD");
if (!ld || !*ld) ld = "ld";
StringArray arr = {};
strarray_push(&arr, "ld");
strarray_push(&arr, ld);
strarray_push(&arr, "-o");
strarray_push(&arr, output);
strarray_push(&arr, "-m");
strarray_push(&arr, "elf_x86_64");
if (opt_shared) {
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o");
} else {
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crt1.o");
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o");
}
strarray_push(&arr, "-L/usr/lib/gcc/x86_64-linux-gnu/9");
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/usr/lib64");
strarray_push(&arr, "-L/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/lib64");
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/usr/lib");
strarray_push(&arr, "-L/lib");
if (!opt_static) {
strarray_push(&arr, "-dynamic-linker");
strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2");
}
for (int i = 0; i < ld_extra_args.len; i++)
strarray_push(&arr, "-z");
strarray_push(&arr, "max-page-size=0x1000");
strarray_push(&arr, "-mnostdlib");
strarray_push(&arr, "--gc-sections");
strarray_push(&arr, "--build-id=none");
strarray_push(&arr, "--no-dynamic-linker");
strarray_push(&arr, "-Ttext-segment=0x400000");
strarray_push(&arr, "-T");
strarray_push(&arr, LDS);
strarray_push(&arr, APE);
strarray_push(&arr, CRT);
for (int i = 0; i < ld_extra_args.len; i++) {
strarray_push(&arr, ld_extra_args.data[i]);
for (int i = 0; i < inputs->len; i++) strarray_push(&arr, inputs->data[i]);
if (opt_static) {
strarray_push(&arr, "--start-group");
strarray_push(&arr, "-lgcc");
strarray_push(&arr, "-lgcc_eh");
strarray_push(&arr, "-lc");
strarray_push(&arr, "--end-group");
} else {
strarray_push(&arr, "-lc");
strarray_push(&arr, "-lgcc");
strarray_push(&arr, "--as-needed");
strarray_push(&arr, "-lgcc_s");
strarray_push(&arr, "--no-as-needed");
}
if (opt_shared)
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o");
else
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o");
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crtn.o");
for (int i = 0; i < inputs->len; i++) {
strarray_push(&arr, inputs->data[i]);
}
strarray_push(&arr, NULL);
run_subprocess(arr.data);
}
static FileType get_file_type(char *filename) {
if (opt_x != FILE_NONE) return opt_x;
if (ends_with(filename, ".a")) return FILE_AR;
if (ends_with(filename, ".so")) return FILE_DSO;
if (ends_with(filename, ".o")) return FILE_OBJ;
if (ends_with(filename, ".c")) return FILE_C;
if (ends_with(filename, ".s")) return FILE_ASM;
error("<command line>: unknown file extension: %s", filename);
}
int main(int argc, char **argv) {
showcrashreports();
atexit(cleanup);
init_macros();
parse_args(argc, argv);
if (opt_cc1) {
add_default_include_paths(argv[0]);
cc1();
return 0;
}
if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
StringArray ld_args = {};
for (int i = 0; i < input_paths.len; i++) {
char *input = input_paths.data[i];
if (!strncmp(input, "-l", 2)) {
strarray_push(&ld_args, input);
continue;
}
if (!strncmp(input, "-Wl,", 4)) {
char *s = strdup(input + 4);
char *arg = strtok(s, ",");
@ -661,43 +629,38 @@ int main(int argc, char **argv) {
}
continue;
}
char *output;
if (opt_o)
if (opt_o) {
output = opt_o;
else if (opt_S)
} else if (opt_S) {
output = replace_extn(input, ".s");
else
} else {
output = replace_extn(input, ".o");
}
FileType type = get_file_type(input);
// Handle .o or .a
if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) {
strarray_push(&ld_args, input);
continue;
}
// Handle .s
if (type == FILE_ASM) {
if (!opt_S) assemble(input, output);
if (!opt_S) {
assemble(input, output);
}
continue;
}
assert(type == FILE_C);
// Just preprocess
if (opt_E || opt_M) {
run_cc1(argc, argv, input, NULL);
continue;
}
// Compile
if (opt_S) {
run_cc1(argc, argv, input, output);
continue;
}
// Compile and assemble
if (opt_c) {
char *tmp = create_tmpfile();
@ -705,7 +668,6 @@ int main(int argc, char **argv) {
assemble(tmp, output);
continue;
}
// Compile, assemble and link
char *tmp1 = create_tmpfile();
char *tmp2 = create_tmpfile();
@ -714,7 +676,8 @@ int main(int argc, char **argv) {
strarray_push(&ld_args, tmp2);
continue;
}
if (ld_args.len > 0) run_linker(&ld_args, opt_o ? opt_o : "a.out");
if (ld_args.len > 0) {
run_linker(&ld_args, opt_o ? opt_o : "a.out");
}
return 0;
}

View file

@ -1,21 +1,21 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _POSIX_C_SOURCE 200809L
#include "libc/assert.h"
#include "libc/bits/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/weirdtypes.h"
#include "libc/conv/conv.h"
#include "libc/conv/itoa.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
@ -25,30 +25,38 @@ COSMOPOLITAN_C_START_
#include "libc/unicode/unicode.h"
#include "libc/x/x.h"
#include "third_party/gdtoa/gdtoa.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#pragma GCC diagnostic ignored "-Wswitch"
#ifndef __GNUC__
#define __attribute__(x)
#endif
typedef struct Type Type;
typedef struct Node Node;
typedef struct Member Member;
typedef struct Relocation Relocation;
typedef struct Asm Asm;
typedef struct AsmOperand AsmOperand;
typedef struct File File;
typedef struct FpClassify FpClassify;
typedef struct Hideset Hideset;
typedef struct Member Member;
typedef struct Node Node;
typedef struct Obj Obj;
typedef struct Relocation Relocation;
typedef struct Relocation Relocation;
typedef struct StaticAsm StaticAsm;
typedef struct StringArray StringArray;
typedef struct Token Token;
typedef struct TokenStack TokenStack;
typedef struct Type Type;
//
// strarray.c
//
typedef struct {
struct StringArray {
char **data;
int capacity;
int len;
} StringArray;
};
void strarray_push(StringArray *arr, char *s);
void strarray_push(StringArray *, char *);
//
// tokenize.c
@ -64,74 +72,144 @@ typedef enum {
TK_EOF, // End-of-file markers
} TokenKind;
typedef struct {
struct File {
char *name;
int file_no;
char *contents;
// For #line directive
char *display_name;
int line_delta;
} File;
};
// Token type
typedef struct Token Token;
struct Token {
TokenKind kind; // Token kind
Token *next; // Next token
int64_t val; // If kind is TK_NUM, its value
long double fval; // If kind is TK_NUM, its value
char *loc; // Token location
int len; // Token length
Type *ty; // Used if TK_NUM or TK_STR
char *str; // String literal contents including terminating '\0'
File *file; // Source location
char *filename; // Filename
int line_no; // Line number
int line_delta; // Line number
bool at_bol; // True if this token is at beginning of line
bool has_space; // True if this token follows a space character
Token *next; // Next token
char *loc; // Token location
Type *ty; // Used if TK_NUM or TK_STR
File *file; // Source location
char *filename; // Filename
Hideset *hideset; // For macro expansion
Token *origin; // If this is expanded from a macro, the original token
union {
int64_t val; // If kind is TK_NUM, its value
long double fval; // If kind is TK_NUM, its value
char *str; // String literal contents including terminating '\0'
};
};
noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
noreturn void error_at(char *loc, char *fmt, ...)
__attribute__((format(printf, 2, 3)));
noreturn void error_tok(Token *tok, char *fmt, ...)
__attribute__((format(printf, 2, 3)));
void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
bool equal(Token *tok, char *op);
Token *skip(Token *tok, char *op);
bool consume(Token **rest, Token *tok, char *str);
void convert_pp_tokens(Token *tok);
File **get_input_files(void);
File *new_file(char *name, int file_no, char *contents);
Token *tokenize_string_literal(Token *tok, Type *basety);
Token *tokenize(File *file);
Token *tokenize_file(char *filename);
void error(char *, ...)
__attribute__((__noreturn__, __format__(__printf__, 1, 2)));
void error_at(char *, char *, ...)
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
void error_tok(Token *, char *, ...)
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
void warn_tok(Token *, char *, ...)
__attribute__((__format__(__printf__, 2, 3)));
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
File **get_input_files(void);
File *new_file(char *, int, char *);
Token *skip(Token *, char *);
Token *tokenize(File *);
Token *tokenize_file(char *);
Token *tokenize_string_literal(Token *, Type *);
bool consume(Token **, Token *, char *, size_t);
bool equal(Token *, char *, size_t);
void convert_pp_tokens(Token *);
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
#define EQUAL(T, S) equal(T, S, strlen(S))
#define CONSUME(R, T, S) consume(R, T, S, strlen(S))
//
// preprocess.c
//
char *format(char *fmt, ...);
char *search_include_paths(char *filename);
bool file_exists(char *path);
char *search_include_paths(char *);
void init_macros(void);
void define_macro(char *name, char *buf);
void undef_macro(char *name);
Token *preprocess(Token *tok);
void define_macro(char *, char *);
void undef_macro(char *);
Token *preprocess(Token *);
//
// asm.c
//
#define kAsmImm 1
#define kAsmMem 2
#define kAsmReg 4
#define kAsmMmx 8
#define kAsmXmm 16
#define kAsmFpu 32
#define kAsmRaw 64
#define kAsmFlag 128
struct AsmOperand {
uint8_t reg;
uint8_t type;
char flow;
char x87mask;
bool isused;
int regmask;
int predicate;
char *str;
Node *node;
Token *tok;
int64_t val;
char **label;
};
struct Asm {
int n;
char *str;
Token *tok;
AsmOperand ops[20];
bool isgnu;
bool flagclob;
uint8_t x87clob;
uint16_t regclob;
uint16_t xmmclob;
};
struct StaticAsm {
StaticAsm *next;
Asm *body;
};
extern StaticAsm *staticasms;
Asm *asm_stmt(Token **, Token *);
void flushln(void);
void gen_addr(Node *);
void gen_asm(Asm *);
void gen_expr(Node *);
void pop(char *);
void popreg(char *);
void print_loc(int64_t, int64_t);
void push(void);
void pushreg(char *);
//
// fpclassify.c
//
struct FpClassify {
Node *node;
int args[5];
};
void gen_fpclassify(FpClassify *);
//
// parse.c
//
// Variable or function
typedef struct Obj Obj;
struct Obj {
Obj *next;
char *name; // Variable name
@ -139,31 +217,36 @@ struct Obj {
Token *tok; // representative token
bool is_local; // local or global/function
int align; // alignment
// Local variable
int offset;
// Global variable or function
bool is_function;
bool is_definition;
bool is_static;
bool is_weak;
bool is_externally_visible;
char *asmname;
char *section;
char *visibility;
// Global variable
bool is_tentative;
bool is_string_literal;
bool is_tls;
char *init_data;
Relocation *rel;
// Function
bool is_inline;
bool is_aligned;
bool is_noreturn;
bool is_destructor;
bool is_constructor;
int stack_size;
Obj *params;
Node *body;
Obj *locals;
Obj *va_area;
Obj *alloca_bottom;
int stack_size;
// Static inline function
// Dead Code Elimination
bool is_live;
bool is_root;
StringArray refs;
@ -172,7 +255,6 @@ struct Obj {
// Global variable can be initialized either by a constant expression
// or a pointer to another global variable. This struct represents the
// latter.
typedef struct Relocation Relocation;
struct Relocation {
Relocation *next;
int offset;
@ -180,127 +262,139 @@ struct Relocation {
long addend;
};
// AST node
typedef enum {
ND_NULL_EXPR, // Do nothing
ND_ADD, // +
ND_SUB, // -
ND_MUL, // *
ND_DIV, // /
ND_NEG, // unary -
ND_MOD, // %
ND_BITAND, // &
ND_BITOR, // |
ND_BITXOR, // ^
ND_SHL, // <<
ND_SHR, // >>
ND_EQ, // ==
ND_NE, // !=
ND_LT, // <
ND_LE, // <=
ND_ASSIGN, // =
ND_COND, // ?:
ND_COMMA, // ,
ND_MEMBER, // . (struct member access)
ND_ADDR, // unary &
ND_DEREF, // unary *
ND_NOT, // !
ND_BITNOT, // ~
ND_LOGAND, // &&
ND_LOGOR, // ||
ND_RETURN, // "return"
ND_IF, // "if"
ND_FOR, // "for" or "while"
ND_DO, // "do"
ND_SWITCH, // "switch"
ND_CASE, // "case"
ND_BLOCK, // { ... }
ND_GOTO, // "goto"
ND_GOTO_EXPR, // "goto" labels-as-values
ND_LABEL, // Labeled statement
ND_LABEL_VAL, // [GNU] Labels-as-values
ND_FUNCALL, // Function call
ND_EXPR_STMT, // Expression statement
ND_STMT_EXPR, // Statement expression
ND_VAR, // Variable
ND_VLA_PTR, // VLA designator
ND_NUM, // Integer
ND_CAST, // Type cast
ND_MEMZERO, // Zero-clear a stack variable
ND_ASM, // "asm"
ND_CAS, // Atomic compare-and-swap
ND_EXCH, // Atomic exchange
ND_NULL_EXPR, // Do nothing
ND_ADD, // +
ND_SUB, // -
ND_MUL, // *
ND_DIV, // /
ND_NEG, // unary -
ND_MOD, // %
ND_BITAND, // &
ND_BITOR, // |
ND_BITXOR, // ^
ND_SHL, // <<
ND_SHR, // >>
ND_EQ, // ==
ND_NE, // !=
ND_LT, // <
ND_LE, // <=
ND_ASSIGN, // =
ND_COND, // ?:
ND_COMMA, // ,
ND_MEMBER, // . (struct member access)
ND_ADDR, // unary &
ND_DEREF, // unary *
ND_NOT, // !
ND_BITNOT, // ~
ND_LOGAND, // &&
ND_LOGOR, // ||
ND_RETURN, // "return"
ND_IF, // "if"
ND_FOR, // "for" or "while"
ND_DO, // "do"
ND_SWITCH, // "switch"
ND_CASE, // "case"
ND_BLOCK, // { ... }
ND_GOTO, // "goto"
ND_GOTO_EXPR, // "goto" labels-as-values
ND_LABEL, // Labeled statement
ND_LABEL_VAL, // [GNU] Labels-as-values
ND_FUNCALL, // Function call
ND_EXPR_STMT, // Expression statement
ND_STMT_EXPR, // Statement expression
ND_VAR, // Variable
ND_VLA_PTR, // VLA designator
ND_NUM, // Integer
ND_CAST, // Type cast
ND_MEMZERO, // Zero-clear a stack variable
ND_ASM, // "asm"
ND_CAS, // Atomic compare-and-swap
ND_EXCH, // Atomic exchange
ND_FPCLASSIFY, // floating point classify
} NodeKind;
// AST node type
struct Node {
NodeKind kind; // Node kind
Node *next; // Next node
Type *ty; // Type, e.g. int or pointer to int
Token *tok; // Representative token
Node *lhs; // Left-hand side
Node *rhs; // Right-hand side
Node *lhs; // Left-hand side
Node *rhs; // Right-hand side
// "if" or "for" statement
Node *cond;
Node *then;
Node *els;
Node *init;
Node *inc;
// "break" and "continue" labels
char *brk_label;
char *cont_label;
// Block or statement expression
Node *body;
// Struct member access
Member *member;
// Function call
Type *func_ty;
Node *args;
bool pass_by_stack;
Obj *ret_buffer;
// Goto or labeled statement, or labels-as-values
char *label;
char *unique_label;
Node *goto_next;
// Switch
Node *case_next;
Node *default_case;
// Case
long begin;
long end;
// "asm" string literal
char *asm_str;
// Atomic compare-and-swap
Node *cas_addr;
Node *cas_old;
Node *cas_new;
// Atomic op= operators
Obj *atomic_addr;
Node *atomic_expr;
// Variable
Obj *var;
// Numeric literal
int64_t val;
long double fval;
union {
struct {
// Function call
Type *func_ty;
Node *args;
bool pass_by_stack;
Obj *ret_buffer;
};
struct {
// Switch
Node *case_next;
Node *default_case;
// Goto or labeled statement, or labels-as-values
char *label;
char *unique_label;
Node *goto_next;
// "break" and "continue" labels
char *brk_label;
char *cont_label;
// Case
long begin;
long end;
};
struct {
// Struct member access
Member *member;
};
struct {
// Assembly
Asm *azm;
};
struct {
// Atomic compare-and-swap
Node *cas_addr;
Node *cas_old;
Node *cas_new;
};
struct {
// Atomic op= operators
Obj *atomic_addr;
Node *atomic_expr;
};
struct {
// Variable
Obj *var;
};
struct {
// Numeric literal
int64_t val;
long double fval;
};
struct {
FpClassify *fpc;
};
};
};
Node *new_cast(Node *expr, Type *ty);
int64_t const_expr(Token **rest, Token *tok);
Obj *parse(Token *tok);
Node *expr(Token **, Token *);
Node *new_cast(Node *, Type *);
Node *new_node(NodeKind, Token *);
Obj *parse(Token *);
bool is_const_expr(Node *);
char *ConsumeStringLiteral(Token **, Token *);
int64_t const_expr(Token **, Token *);
int64_t eval(Node *);
int64_t eval2(Node *, char ***);
//
// type.c
@ -313,6 +407,7 @@ typedef enum {
TY_SHORT,
TY_INT,
TY_LONG,
TY_INT128,
TY_FLOAT,
TY_DOUBLE,
TY_LDOUBLE,
@ -332,7 +427,6 @@ struct Type {
bool is_unsigned; // unsigned or signed
bool is_atomic; // true if _Atomic
Type *origin; // for type compatibility check
// Pointer-to or array-of type. We intentionally use the same member
// to represent pointer/array duality in C.
//
@ -342,23 +436,20 @@ struct Type {
// naturally handled as if it were "pointer to T", as required by
// the C spec.
Type *base;
// Declaration
Token *name;
Token *name_pos;
// Array
int array_len;
int vector_size;
// Variable-length array
Node *vla_len; // # of elements
Obj *vla_size; // sizeof() value
// Struct
Member *members;
bool is_flexible;
bool is_packed;
bool is_aligned;
// Function type
Type *return_ty;
Type *params;
@ -375,59 +466,70 @@ struct Member {
int idx;
int align;
int offset;
// Bitfield
bool is_bitfield;
int bit_offset;
int bit_width;
};
extern Type *ty_void;
extern Type *ty_bool;
extern Type ty_void[1];
extern Type ty_bool[1];
extern Type ty_char[1];
extern Type ty_short[1];
extern Type ty_int[1];
extern Type ty_long[1];
extern Type ty_int128[1];
extern Type ty_uchar[1];
extern Type ty_ushort[1];
extern Type ty_uint[1];
extern Type ty_ulong[1];
extern Type ty_uint128[1];
extern Type ty_float[1];
extern Type ty_double[1];
extern Type ty_ldouble[1];
extern Type *ty_char;
extern Type *ty_short;
extern Type *ty_int;
extern Type *ty_long;
extern Type *ty_uchar;
extern Type *ty_ushort;
extern Type *ty_uint;
extern Type *ty_ulong;
extern Type *ty_float;
extern Type *ty_double;
extern Type *ty_ldouble;
bool is_integer(Type *ty);
bool is_flonum(Type *ty);
bool is_numeric(Type *ty);
bool is_compatible(Type *t1, Type *t2);
Type *copy_type(Type *ty);
Type *pointer_to(Type *base);
Type *func_type(Type *return_ty);
Type *array_of(Type *base, int size);
Type *vla_of(Type *base, Node *expr);
bool is_integer(Type *);
bool is_flonum(Type *);
bool is_numeric(Type *);
bool is_compatible(Type *, Type *);
Type *copy_type(Type *);
Type *pointer_to(Type *);
Type *func_type(Type *);
Type *array_of(Type *, int);
Type *vla_of(Type *, Node *);
Type *enum_type(void);
Type *struct_type(void);
void add_type(Node *node);
void add_type(Node *);
//
// cast.c
//
void gen_cast(Type *, Type *);
//
// codegen.c
//
void codegen(Obj *prog, FILE *out);
int align_to(int n, int align);
extern int depth;
extern FILE *output_stream;
int align_to(int, int);
int count(void);
void cmp_zero(Type *);
void codegen(Obj *, FILE *);
void gen_stmt(Node *);
void println(char *, ...) __attribute__((__format__(__printf__, 1, 2)));
//
// unicode.c
//
int encode_utf8(char *buf, uint32_t c);
uint32_t decode_utf8(char **new_pos, char *p);
bool is_ident1(uint32_t c);
bool is_ident2(uint32_t c);
int str_width(char *p, int len);
int encode_utf8(char *, uint32_t);
uint32_t decode_utf8(char **, char *);
bool is_ident1(uint32_t);
bool is_ident2(uint32_t);
int str_width(char *, int);
//
// hashmap.c
@ -445,29 +547,28 @@ typedef struct {
int used;
} HashMap;
void *hashmap_get(HashMap *map, char *key);
void *hashmap_get2(HashMap *map, char *key, int keylen);
void hashmap_put(HashMap *map, char *key, void *val);
void hashmap_put2(HashMap *map, char *key, int keylen, void *val);
void hashmap_delete(HashMap *map, char *key);
void hashmap_delete2(HashMap *map, char *key, int keylen);
void *hashmap_get(HashMap *, char *);
void *hashmap_get2(HashMap *, char *, int);
void hashmap_put(HashMap *, char *, void *);
void hashmap_put2(HashMap *, char *, int, void *);
void hashmap_delete(HashMap *, char *);
void hashmap_delete2(HashMap *, char *, int);
void hashmap_test(void);
//
// main.c
// chibicc.c
//
extern StringArray include_paths;
extern bool opt_fpic;
extern bool opt_fcommon;
extern bool opt_fpic;
extern bool opt_verbose;
extern bool opt_mpopcnt;
extern char *base_file;
typedef struct StaticAsm {
struct StaticAsm *next;
Node *body;
} StaticAsm;
extern struct StaticAsm *staticasms;
extern bool opt_pg;
extern bool opt_mfentry;
extern bool opt_mnop_mcount;
extern bool opt_mrecord_mcount;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,70 +1,109 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# C Compiler
#
# OVERVIEW
#
# This makefile compiles and runs each test twice. The first with
# GCC-built chibicc, and a second time with chibicc-built chibicc
CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com.dbg
CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
CHIBICC_FLAGS = \
-fno-common \
-include libc/integral/normalize.inc
PKGS += THIRD_PARTY_CHIBICC
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(THIRD_PARTY_CHIBICC_A)
THIRD_PARTY_CHIBICC_A = o/$(MODE)/third_party/chibicc/chibicc.a
THIRD_PARTY_CHIBICC_A_FILES := $(wildcard third_party/chibicc/*)
THIRD_PARTY_CHIBICC_A_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_A_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_BINS = \
o/$(MODE)/third_party/chibicc/chibicc.com
THIRD_PARTY_CHIBICC_BINS = \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
o/$(MODE)/third_party/chibicc/chibicc.com \
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg \
o/$(MODE)/third_party/chibicc/chibicc2.com
THIRD_PARTY_CHIBICC_A_SRCS = \
$(THIRD_PARTY_CHIBICC_A_SRCS_S) \
$(THIRD_PARTY_CHIBICC_A_SRCS_C)
THIRD_PARTY_CHIBICC_A_OBJS = \
$(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_CHIBICC_A_OBJS = \
$(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_CHIBICC_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(THIRD_PARTY_CHIBICC_A_SRCS_C:%.c=o/$(MODE)/%.o)
THIRD_PARTY_CHIBICC_A_CHECKS = \
$(THIRD_PARTY_CHIBICC_A).pkg \
THIRD_PARTY_CHIBICC_A_CHECKS = \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_FMT \
LIBC_NEXGEN32E \
LIBC_UNICODE \
LIBC_STDIO \
LIBC_MEM \
LIBC_LOG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_TIME \
LIBC_X \
LIBC_CONV \
LIBC_RUNTIME \
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_CONV \
LIBC_FMT \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_LOG \
LIBC_STR \
LIBC_STUBS \
LIBC_TIME \
LIBC_UNICODE \
LIBC_X \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA
THIRD_PARTY_CHIBICC_A_DEPS := \
THIRD_PARTY_CHIBICC_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_CHIBICC_A): \
third_party/chibicc/ \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(THIRD_PARTY_CHIBICC_A): \
third_party/chibicc/ \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(THIRD_PARTY_CHIBICC_A_OBJS)
$(THIRD_PARTY_CHIBICC_A).pkg: \
$(THIRD_PARTY_CHIBICC_A_OBJS) \
$(THIRD_PARTY_CHIBICC_A).pkg: \
$(THIRD_PARTY_CHIBICC_A_OBJS) \
$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/third_party/chibicc/%.com.dbg: \
$(THIRD_PARTY_CHIBICC_A_DEPS) \
$(THIRD_PARTY_CHIBICC_A) \
o/$(MODE)/third_party/chibicc/%.o \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(CRT) \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
$(THIRD_PARTY_CHIBICC_A_DEPS) \
$(THIRD_PARTY_CHIBICC_A) \
o/$(MODE)/third_party/chibicc/chibicc.o \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
$(THIRD_PARTY_CHIBICC_A_DEPS) \
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.o) \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/third_party/chibicc/chibicc.o: \
CPPFLAGS += \
-DCRT=\"$(CRT)\" \
-DAPE=\"o/$(MODE)/ape/ape.o\" \
-DLDS=\"o/$(MODE)/ape/ape.lds\"
o/$(MODE)/third_party/chibicc/chibicc.chibicc.s: \
CHIBICC_FLAGS += \
-DCRT=\"$(CRT)\" \
-DAPE=\"o/$(MODE)/ape/ape.o\" \
-DLDS=\"o/$(MODE)/ape/ape.lds\"
o/$(MODE)/%.chibicc.s: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg
@ACTION=CHIBICC TARGET=$@ build/do $(CHIBICC) $(CHIBICC_FLAGS) -S -o $@ $<
o/$(MODE)/%.chibicc2.s: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
@ACTION=CHIBICC2 TARGET=$@ build/do $(CHIBICC2) $(CHIBICC_FLAGS) -S -o $@ $<
THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)))
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_CHIBICC_HDRS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_HDRS))
@ -73,6 +112,8 @@ THIRD_PARTY_CHIBICC_OBJS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_O
$(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk
.PHONY: o/$(MODE)/third_party/chibicc
o/$(MODE)/third_party/chibicc: \
$(THIRD_PARTY_CHIBICC_BINS) \
$(THIRD_PARTY_CHIBICC_CHECKS)
o/$(MODE)/third_party/chibicc: \
o/$(MODE)/third_party/chibicc/test \
$(THIRD_PARTY_CHIBICC_BINS) \
$(THIRD_PARTY_CHIBICC_CHECKS) \
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.s)

File diff suppressed because it is too large Load diff

145
third_party/chibicc/fpclassify.c vendored Normal file
View file

@ -0,0 +1,145 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "third_party/chibicc/chibicc.h"
/**
* @fileoverview __builtin_fpclassify() implementation
*/
#define FPCLASSIFY_FLOAT \
"\tmovaps\t%%xmm0,%%xmm1\n\
\tmov\t$0x7fffffff,%%eax\n\
\tmovd\t%%eax,%%xmm2\n\
\tandps\t%%xmm2,%%xmm1\n\
\tmov\t$%d,%%eax\n\
\tucomiss\t%%xmm1,%%xmm1\n\
\tjp\t9f\n\
\tmov\t$0x7f7fffff,%%edi\n\
\tmovd\t%%edi,%%xmm2\n\
\tucomiss\t%%xmm2,%%xmm1\n\
\tja\t2f\n\
\tmov\t$0x00800000,%%edi\n\
\tmovd\t%%edi,%%xmm2\n\
\tucomiss\t%%xmm2,%%xmm1\n\
\tjnb\t3f\n\
\txorps\t%%xmm1,%%xmm1\n\
\tucomiss\t%%xmm1,%%xmm0\n\
\tjp\t1f\n\
\tmovl\t$%d,%%eax\n\
\tje\t9f\n\
1:\tmovl\t$%d,%%eax\n\
\tjmp\t9f\n\
2:\tmovl\t$%d,%%eax\n\
\tjmp\t9f\n\
3:\tmovl\t$%d,%%eax\n\
9:"
#define FPCLASSIFY_DOUBLE \
"\tmovapd\t%%xmm0,%%xmm1\n\
\tmov\t$0x7fffffffffffffff,%%rax\n\
\tmovq\t%%rax,%%xmm2\n\
\tandps\t%%xmm2,%%xmm1\n\
\tmov\t$%d,%%eax\n\
\tucomisd\t%%xmm1,%%xmm1\n\
\tjp\t9f\n\
\tmov\t$0x7fefffffffffffff,%%rdi\n\
\tmovq\t%%rdi,%%xmm2\n\
\tucomisd\t%%xmm2,%%xmm1\n\
\tja\t2f\n\
\tmov\t$0x0010000000000000,%%rdi\n\
\tmovq\t%%rdi,%%xmm2\n\
\tucomisd\t%%xmm2,%%xmm1\n\
\tjnb\t3f\n\
\txorps\t%%xmm1,%%xmm1\n\
\tucomisd\t%%xmm1,%%xmm0\n\
\tjp\t1f\n\
\tmovl\t$%d,%%eax\n\
\tje\t9f\n\
1:\tmovl\t$%d,%%eax\n\
\tjmp\t9f\n\
2:\tmovl\t$%d,%%eax\n\
\tjmp\t9f\n\
3:\tmovl\t$%d,%%eax\n\
9:"
#define FPCLASSIFY_LDOUBLE \
"\tmov\t$%d,%%eax\n\
\tfld\t%%st\n\
\tfabs\n\
\tfucomi\t%%st,%%st\n\
\tjp\t6f\n\
\tpush\t$0x7ffe\n\
\tpush\t$-1\n\
\tfldt\t(%%rsp)\n\
\tadd\t$16,%%rsp\n\
\tfxch\n\
\tmov\t$%d,%%eax\n\
\tfucomi\n\
\tfstp\t%%st(1)\n\
\tja\t7f\n\
\tmov\t$1,%%edi\n\
\tpush\t%%rdi\n\
\tror\t%%rdi\n\
\tpush\t%%rdi\n\
\tfldt\t(%%rsp)\n\
\tadd\t$16,%%rsp\n\
\tfxch\n\
\tmov\t$%d,%%eax\n\
\tfucomip\n\
\tfstp\t%%st\n\
\tjnb\t8f\n\
\tfldz\n\
\tfxch\n\
\tfucomip\n\
\tfstp\t%%st\n\
\tjp\t5f\n\
\tmov\t$%d,%%eax\n\
\tje\t9f\n\
5:\tmov\t$%d,%%eax\n\
\tjmp\t9f\n\
6:\tfstp\t%%st\n\
\tfstp\t%%st\n\
\tjmp\t9f\n\
7:\tfstp\t%%st\n\
\tfstp\t%%st\n\
\tjmp\t9f\n\
8:\tfstp\t%%st\n\
9:"
void gen_fpclassify(FpClassify *fpc) {
int fpnan = fpc->args[0];
int fpinf = fpc->args[1];
int fpnorm = fpc->args[2];
int fpsubnorm = fpc->args[3];
int fpzero = fpc->args[4];
gen_expr(fpc->node);
switch (fpc->node->ty->kind) {
case TY_FLOAT:
println(FPCLASSIFY_FLOAT, fpnan, fpzero, fpsubnorm, fpinf, fpnorm);
break;
case TY_DOUBLE:
println(FPCLASSIFY_DOUBLE, fpnan, fpzero, fpsubnorm, fpinf, fpnorm);
break;
case TY_LDOUBLE:
println(FPCLASSIFY_LDOUBLE, fpnan, fpinf, fpnorm, fpzero, fpsubnorm);
break;
default:
UNREACHABLE();
}
}

View file

@ -20,7 +20,7 @@ static void rehash(HashMap *map) {
int nkeys = 0;
for (int i = 0; i < map->capacity; i++)
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++;
int cap = map->capacity;
size_t cap = map->capacity;
while ((nkeys * 100) / cap >= 50) cap = cap * 2;
// Create a new hashmap and copy all key-values.
HashMap map2 = {};
@ -44,7 +44,7 @@ static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
if (!map->buckets) return NULL;
uint64_t hash = fnv_hash(key, keylen);
for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)];
if (match(ent, key, keylen)) return ent;
if (ent->key == NULL) return NULL;
}
@ -58,7 +58,7 @@ static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {
if ((map->used * 100) / map->capacity >= 70) rehash(map);
uint64_t hash = fnv_hash(key, keylen);
for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)];
if (match(ent, key, keylen)) return ent;
if (ent->key == TOMBSTONE) {
ent->key = key;
@ -102,29 +102,31 @@ void hashmap_delete2(HashMap *map, char *key, int keylen) {
if (ent) ent->key = TOMBSTONE;
}
#if 0
void hashmap_test(void) {
HashMap *map = calloc(1, sizeof(HashMap));
for (int i = 0; i < 5000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 1000; i < 2000; i++) hashmap_delete(map, format("key %d", i));
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
for (int i = 1000; i < 2000; i++) hashmap_delete(map, xasprintf("key %d", i));
for (int i = 1500; i < 1600; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
for (int i = 0; i < 1000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
for (int i = 1000; i < 1500; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 1500; i < 1600; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
for (int i = 1600; i < 2000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 2000; i < 5000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
for (int i = 5000; i < 6000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
assert(hashmap_get(map, "no such key") == NULL);
printf("OK\n");
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -24,13 +24,27 @@
#include "third_party/chibicc/chibicc.h"
typedef struct CondIncl CondIncl;
typedef struct Hideset Hideset;
typedef struct Macro Macro;
typedef struct MacroArg MacroArg;
typedef struct MacroParam MacroParam;
typedef Token *macro_handler_fn(Token *);
typedef enum {
STR_NONE,
STR_UTF8,
STR_UTF16,
STR_UTF32,
STR_WIDE,
} StringKind;
struct MacroParam {
MacroParam *next;
char *name;
};
typedef struct MacroArg MacroArg;
struct MacroArg {
MacroArg *next;
char *name;
@ -38,9 +52,6 @@ struct MacroArg {
Token *tok;
};
typedef Token *macro_handler_fn(Token *);
typedef struct Macro Macro;
struct Macro {
char *name;
bool is_objlike; // Object-like or function-like
@ -51,7 +62,6 @@ struct Macro {
};
// `#if` can be nested, so we use a stack to manage nested `#if`s.
typedef struct CondIncl CondIncl;
struct CondIncl {
CondIncl *next;
enum { IN_THEN, IN_ELIF, IN_ELSE } ctx;
@ -59,7 +69,6 @@ struct CondIncl {
bool included;
};
typedef struct Hideset Hideset;
struct Hideset {
Hideset *next;
char *name;
@ -70,20 +79,11 @@ static CondIncl *cond_incl;
static HashMap pragma_once;
static int include_next_idx;
static Token *preprocess2(Token *tok);
static Macro *find_macro(Token *tok);
char *format(char *fmt, ...) {
char *res;
va_list va;
va_start(va, fmt);
res = xvasprintf(fmt, va);
va_end(va);
return res;
}
static Token *preprocess2(Token *);
static Macro *find_macro(Token *);
static bool is_hash(Token *tok) {
return tok->at_bol && equal(tok, "#");
return tok->at_bol && EQUAL(tok, "#");
}
// Some preprocessor directives such as #include allow extraneous
@ -118,23 +118,30 @@ static Hideset *new_hideset(char *name) {
static Hideset *hideset_union(Hideset *hs1, Hideset *hs2) {
Hideset head = {};
Hideset *cur = &head;
for (; hs1; hs1 = hs1->next) cur = cur->next = new_hideset(hs1->name);
for (; hs1; hs1 = hs1->next) {
cur = cur->next = new_hideset(hs1->name);
}
cur->next = hs2;
return head.next;
}
static bool hideset_contains(Hideset *hs, char *s, int len) {
for (; hs; hs = hs->next)
if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) return true;
for (; hs; hs = hs->next) {
if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) {
return true;
}
}
return false;
}
static Hideset *hideset_intersection(Hideset *hs1, Hideset *hs2) {
Hideset head = {};
Hideset *cur = &head;
for (; hs1; hs1 = hs1->next)
if (hideset_contains(hs2, hs1->name, strlen(hs1->name)))
for (; hs1; hs1 = hs1->next) {
if (hideset_contains(hs2, hs1->name, strlen(hs1->name))) {
cur = cur->next = new_hideset(hs1->name);
}
}
return head.next;
}
@ -162,12 +169,12 @@ static Token *append(Token *tok1, Token *tok2) {
static Token *skip_cond_incl2(Token *tok) {
while (tok->kind != TK_EOF) {
if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
equal(tok->next, "ifndef"))) {
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
EQUAL(tok->next, "ifndef"))) {
tok = skip_cond_incl2(tok->next->next);
continue;
}
if (is_hash(tok) && equal(tok->next, "endif")) return tok->next->next;
if (is_hash(tok) && EQUAL(tok->next, "endif")) return tok->next->next;
tok = tok->next;
}
return tok;
@ -177,13 +184,13 @@ static Token *skip_cond_incl2(Token *tok) {
// Nested `#if` and `#endif` are skipped.
static Token *skip_cond_incl(Token *tok) {
while (tok->kind != TK_EOF) {
if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
equal(tok->next, "ifndef"))) {
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
EQUAL(tok->next, "ifndef"))) {
tok = skip_cond_incl2(tok->next->next);
continue;
}
if (is_hash(tok) && (equal(tok->next, "elif") || equal(tok->next, "else") ||
equal(tok->next, "endif")))
if (is_hash(tok) && (EQUAL(tok->next, "elif") || EQUAL(tok->next, "else") ||
EQUAL(tok->next, "endif")))
break;
tok = tok->next;
}
@ -239,9 +246,9 @@ static Token *read_const_expr(Token **rest, Token *tok) {
while (tok->kind != TK_EOF) {
// "defined(foo)" or "defined foo" becomes "1" if macro "foo"
// is defined. Otherwise "0".
if (equal(tok, "defined")) {
if (EQUAL(tok, "defined")) {
Token *start = tok;
bool has_paren = consume(&tok, tok->next, "(");
bool has_paren = CONSUME(&tok, tok->next, "(");
if (tok->kind != TK_IDENT)
error_tok(start, "macro name must be an identifier");
Macro *m = find_macro(tok);
@ -310,15 +317,15 @@ static MacroParam *read_macro_params(Token **rest, Token *tok,
char **va_args_name) {
MacroParam head = {};
MacroParam *cur = &head;
while (!equal(tok, ")")) {
while (!EQUAL(tok, ")")) {
if (cur != &head) tok = skip(tok, ",");
if (equal(tok, "...")) {
if (EQUAL(tok, "...")) {
*va_args_name = "__VA_ARGS__";
*rest = skip(tok->next, ")");
return head.next;
}
if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier");
if (equal(tok->next, "...")) {
if (EQUAL(tok->next, "...")) {
*va_args_name = strndup(tok->loc, tok->len);
*rest = skip(tok->next->next, ")");
return head.next;
@ -336,7 +343,7 @@ static void read_macro_definition(Token **rest, Token *tok) {
if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier");
char *name = strndup(tok->loc, tok->len);
tok = tok->next;
if (!tok->has_space && equal(tok, "(")) {
if (!tok->has_space && EQUAL(tok, "(")) {
// Function-like macro
char *va_args_name = NULL;
MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
@ -354,12 +361,12 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
Token *cur = &head;
int level = 0;
for (;;) {
if (level == 0 && equal(tok, ")")) break;
if (level == 0 && !read_rest && equal(tok, ",")) break;
if (level == 0 && EQUAL(tok, ")")) break;
if (level == 0 && !read_rest && EQUAL(tok, ",")) break;
if (tok->kind == TK_EOF) error_tok(tok, "premature end of input");
if (equal(tok, "("))
if (EQUAL(tok, "("))
level++;
else if (equal(tok, ")"))
else if (EQUAL(tok, ")"))
level--;
cur = cur->next = copy_token(tok);
tok = tok->next;
@ -385,7 +392,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params,
}
if (va_args_name) {
MacroArg *arg;
if (equal(tok, ")")) {
if (EQUAL(tok, ")")) {
arg = calloc(1, sizeof(MacroArg));
arg->tok = new_eof(tok);
} else {
@ -454,8 +461,11 @@ static Token *paste(Token *lhs, Token *rhs) {
}
static bool has_varargs(MacroArg *args) {
for (MacroArg *ap = args; ap; ap = ap->next)
if (!strcmp(ap->name, "__VA_ARGS__")) return ap->tok->kind != TK_EOF;
for (MacroArg *ap = args; ap; ap = ap->next) {
if (!strcmp(ap->name, "__VA_ARGS__")) {
return ap->tok->kind != TK_EOF;
}
}
return false;
}
@ -463,10 +473,9 @@ static bool has_varargs(MacroArg *args) {
static Token *subst(Token *tok, MacroArg *args) {
Token head = {};
Token *cur = &head;
while (tok->kind != TK_EOF) {
// "#" followed by a parameter is replaced with stringized actuals.
if (equal(tok, "#")) {
if (EQUAL(tok, "#")) {
MacroArg *arg = find_arg(args, tok->next);
if (!arg)
error_tok(tok->next, "'#' is not followed by a macro parameter");
@ -474,11 +483,10 @@ static Token *subst(Token *tok, MacroArg *args) {
tok = tok->next->next;
continue;
}
// [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded
// to the empty token list. Otherwise, its expaned to `,` and
// __VA_ARGS__.
if (equal(tok, ",") && equal(tok->next, "##")) {
if (EQUAL(tok, ",") && EQUAL(tok->next, "##")) {
MacroArg *arg = find_arg(args, tok->next->next);
if (arg && arg->is_va_args) {
if (arg->tok->kind == TK_EOF) {
@ -490,14 +498,11 @@ static Token *subst(Token *tok, MacroArg *args) {
continue;
}
}
if (equal(tok, "##")) {
if (EQUAL(tok, "##")) {
if (cur == &head)
error_tok(tok, "'##' cannot appear at start of macro expansion");
if (tok->next->kind == TK_EOF)
error_tok(tok, "'##' cannot appear at end of macro expansion");
MacroArg *arg = find_arg(args, tok->next);
if (arg) {
if (arg->tok->kind != TK_EOF) {
@ -508,17 +513,13 @@ static Token *subst(Token *tok, MacroArg *args) {
tok = tok->next->next;
continue;
}
*cur = *paste(cur, tok->next);
tok = tok->next->next;
continue;
}
MacroArg *arg = find_arg(args, tok);
if (arg && equal(tok->next, "##")) {
if (arg && EQUAL(tok->next, "##")) {
Token *rhs = tok->next->next;
if (arg->tok->kind == TK_EOF) {
MacroArg *arg2 = find_arg(args, rhs);
if (arg2) {
@ -530,16 +531,14 @@ static Token *subst(Token *tok, MacroArg *args) {
tok = rhs->next;
continue;
}
for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
cur = cur->next = copy_token(t);
tok = tok->next;
continue;
}
// If __VA_ARG__ is empty, __VA_OPT__(x) is expanded to the
// empty token list. Otherwise, __VA_OPT__(x) is expanded to x.
if (equal(tok, "__VA_OPT__") && equal(tok->next, "(")) {
if (EQUAL(tok, "__VA_OPT__") && EQUAL(tok->next, "(")) {
MacroArg *arg = read_macro_arg_one(&tok, tok->next->next, true);
if (has_varargs(args))
for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
@ -547,7 +546,6 @@ static Token *subst(Token *tok, MacroArg *args) {
tok = skip(tok, ")");
continue;
}
// Handle a macro token. Macro arguments are completely macro-expanded
// before they are substituted into a macro body.
if (arg) {
@ -558,13 +556,11 @@ static Token *subst(Token *tok, MacroArg *args) {
tok = tok->next;
continue;
}
// Handle a non-macro token.
cur = cur->next = copy_token(tok);
tok = tok->next;
continue;
}
cur->next = tok;
return head.next;
}
@ -585,7 +581,9 @@ static bool expand_macro(Token **rest, Token *tok) {
if (m->is_objlike) {
Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
Token *body = add_hideset(m->body, hs);
for (Token *t = body; t->kind != TK_EOF; t = t->next) t->origin = tok;
for (Token *t = body; t->kind != TK_EOF; t = t->next) {
t->origin = tok;
}
*rest = append(body, tok->next);
(*rest)->at_bol = tok->at_bol;
(*rest)->has_space = tok->has_space;
@ -593,7 +591,7 @@ static bool expand_macro(Token **rest, Token *tok) {
}
// If a funclike macro token is not followed by an argument list,
// treat it as a normal identifier.
if (!equal(tok->next, "(")) return false;
if (!EQUAL(tok->next, "(")) return false;
// Function-like macro application
Token *macro_token = tok;
MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name);
@ -614,12 +612,6 @@ static bool expand_macro(Token **rest, Token *tok) {
return true;
}
// Returns true if a given file exists.
bool file_exists(char *path) {
struct stat st;
return !stat(path, &st);
}
char *search_include_paths(char *filename) {
if (filename[0] == '/') return filename;
static HashMap cache;
@ -627,8 +619,8 @@ char *search_include_paths(char *filename) {
if (cached) return cached;
// Search a file from the include paths.
for (int i = 0; i < include_paths.len; i++) {
char *path = format("%s/%s", include_paths.data[i], filename);
if (!file_exists(path)) continue;
char *path = xasprintf("%s/%s", include_paths.data[i], filename);
if (!fileexists(path)) continue;
hashmap_put(&cache, filename, path);
include_next_idx = i + 1;
return path;
@ -639,8 +631,8 @@ char *search_include_paths(char *filename) {
static char *search_include_next(char *filename) {
for (; include_next_idx < include_paths.len; include_next_idx++) {
char *path =
format("%s/%s", include_paths.data[include_next_idx], filename);
if (file_exists(path)) return path;
xasprintf("%s/%s", include_paths.data[include_next_idx], filename);
if (fileexists(path)) return path;
}
return NULL;
}
@ -659,12 +651,12 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {
return strndup(tok->loc + 1, tok->len - 2);
}
// Pattern 2: #include <foo.h>
if (equal(tok, "<")) {
if (EQUAL(tok, "<")) {
// Reconstruct a filename from a sequence of tokens between
// "<" and ">".
Token *start = tok;
// Find closing ">".
for (; !equal(tok, ">"); tok = tok->next)
for (; !EQUAL(tok, ">"); tok = tok->next)
if (tok->at_bol || tok->kind == TK_EOF) error_tok(tok, "expected '>'");
*is_dquote = false;
*rest = skip_line(tok->next);
@ -688,13 +680,13 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {
// #endif
static char *detect_include_guard(Token *tok) {
// Detect the first two lines.
if (!is_hash(tok) || !equal(tok->next, "ifndef")) return NULL;
if (!is_hash(tok) || !EQUAL(tok->next, "ifndef")) return NULL;
tok = tok->next->next;
if (tok->kind != TK_IDENT) return NULL;
char *macro = strndup(tok->loc, tok->len);
tok = tok->next;
if (!is_hash(tok) || !equal(tok->next, "define") ||
!equal(tok->next->next, macro))
if (!is_hash(tok) || !EQUAL(tok->next, "define") ||
!EQUAL(tok->next->next, macro))
return NULL;
// Read until the end of the file.
while (tok->kind != TK_EOF) {
@ -702,9 +694,9 @@ static char *detect_include_guard(Token *tok) {
tok = tok->next;
continue;
}
if (equal(tok->next, "endif") && tok->next->next->kind == TK_EOF)
if (EQUAL(tok->next, "endif") && tok->next->next->kind == TK_EOF)
return macro;
if (equal(tok, "if") || equal(tok, "ifdef") || equal(tok, "ifndef"))
if (EQUAL(tok, "if") || EQUAL(tok, "ifdef") || EQUAL(tok, "ifndef"))
tok = skip_cond_incl(tok->next);
else
tok = tok->next;
@ -732,14 +724,11 @@ static Token *include_file(Token *tok, char *path) {
static void read_line_marker(Token **rest, Token *tok) {
Token *start = tok;
tok = preprocess(copy_line(rest, tok));
if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)
error_tok(tok, "invalid line marker");
start->file->line_delta = tok->val - start->line_no;
tok = tok->next;
if (tok->kind == TK_EOF) return;
if (tok->kind != TK_STR) error_tok(tok, "filename expected");
start->file->display_name = tok->str;
}
@ -749,11 +738,9 @@ static void read_line_marker(Token **rest, Token *tok) {
static Token *preprocess2(Token *tok) {
Token head = {};
Token *cur = &head;
while (tok->kind != TK_EOF) {
// If it is a macro, expand it.
if (expand_macro(&tok, tok)) continue;
// Pass through if it is not a "#".
if (!is_hash(tok)) {
tok->line_delta = tok->file->line_delta;
@ -762,42 +749,35 @@ static Token *preprocess2(Token *tok) {
tok = tok->next;
continue;
}
Token *start = tok;
tok = tok->next;
if (equal(tok, "include")) {
if (EQUAL(tok, "include")) {
bool is_dquote;
char *filename = read_include_filename(&tok, tok->next, &is_dquote);
if (filename[0] != '/' && is_dquote) {
char *path =
format("%s/%s", dirname(strdup(start->file->name)), filename);
if (file_exists(path)) {
xasprintf("%s/%s", dirname(strdup(start->file->name)), filename);
if (fileexists(path)) {
tok = include_file(tok, path);
continue;
}
}
char *path = search_include_paths(filename);
tok = include_file(tok, path ? path : filename);
continue;
}
if (equal(tok, "include_next")) {
if (EQUAL(tok, "include_next")) {
bool ignore;
char *filename = read_include_filename(&tok, tok->next, &ignore);
char *path = search_include_next(filename);
tok = include_file(tok, path ? path : filename);
continue;
}
if (equal(tok, "define")) {
if (EQUAL(tok, "define")) {
read_macro_definition(&tok, tok->next);
continue;
}
if (equal(tok, "undef")) {
if (EQUAL(tok, "undef")) {
tok = tok->next;
if (tok->kind != TK_IDENT)
error_tok(tok, "macro name must be an identifier");
@ -805,90 +785,74 @@ static Token *preprocess2(Token *tok) {
tok = skip_line(tok->next);
continue;
}
if (equal(tok, "if")) {
if (EQUAL(tok, "if")) {
long val = eval_const_expr(&tok, tok);
push_cond_incl(start, val);
if (!val) tok = skip_cond_incl(tok);
continue;
}
if (equal(tok, "ifdef")) {
if (EQUAL(tok, "ifdef")) {
bool defined = find_macro(tok->next);
push_cond_incl(tok, defined);
tok = skip_line(tok->next->next);
if (!defined) tok = skip_cond_incl(tok);
continue;
}
if (equal(tok, "ifndef")) {
if (EQUAL(tok, "ifndef")) {
bool defined = find_macro(tok->next);
push_cond_incl(tok, !defined);
tok = skip_line(tok->next->next);
if (defined) tok = skip_cond_incl(tok);
continue;
}
if (equal(tok, "elif")) {
if (EQUAL(tok, "elif")) {
if (!cond_incl || cond_incl->ctx == IN_ELSE)
error_tok(start, "stray #elif");
cond_incl->ctx = IN_ELIF;
if (!cond_incl->included && eval_const_expr(&tok, tok))
cond_incl->included = true;
else
tok = skip_cond_incl(tok);
continue;
}
if (equal(tok, "else")) {
if (EQUAL(tok, "else")) {
if (!cond_incl || cond_incl->ctx == IN_ELSE)
error_tok(start, "stray #else");
cond_incl->ctx = IN_ELSE;
tok = skip_line(tok->next);
if (cond_incl->included) tok = skip_cond_incl(tok);
continue;
}
if (equal(tok, "endif")) {
if (EQUAL(tok, "endif")) {
if (!cond_incl) error_tok(start, "stray #endif");
cond_incl = cond_incl->next;
tok = skip_line(tok->next);
continue;
}
if (equal(tok, "line")) {
if (EQUAL(tok, "line")) {
read_line_marker(&tok, tok->next);
continue;
}
if (tok->kind == TK_PP_NUM) {
read_line_marker(&tok, tok);
continue;
}
if (equal(tok, "pragma") && equal(tok->next, "once")) {
if (EQUAL(tok, "pragma") && EQUAL(tok->next, "once")) {
hashmap_put(&pragma_once, tok->file->name, (void *)1);
tok = skip_line(tok->next->next);
continue;
}
if (equal(tok, "pragma")) {
if (EQUAL(tok, "pragma")) {
do {
tok = tok->next;
} while (!tok->at_bol);
continue;
}
if (equal(tok, "error")) error_tok(tok, "error");
if (EQUAL(tok, "error")) error_tok(tok, "error");
// `#`-only line is legal. It's called a null directive.
if (tok->at_bol) continue;
error_tok(tok, "invalid preprocessor directive");
}
cur->next = tok;
return head.next;
}
@ -944,7 +908,7 @@ static Token *base_file_macro(Token *tmpl) {
// __DATE__ is expanded to the current date, e.g. "May 17 2020".
static char *format_date(struct tm *tm) {
static char mon[][4] = {
_Alignas(char) static char mon[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
@ -962,48 +926,320 @@ static char *format_time(struct tm *tm) {
}
void init_macros(void) {
// Define predefined macros
define_macro("_LP64", "1");
define_macro("__STRICT_ANSI__", "1");
define_macro("__C99_MACRO_WITH_VA_ARGS", "1");
define_macro("__ELF__", "1");
define_macro("__LP64__", "1");
define_macro("__SIZEOF_DOUBLE__", "8");
define_macro("__SIZEOF_FLOAT__", "4");
define_macro("__SIZEOF_INT__", "4");
define_macro("__SIZEOF_LONG_DOUBLE__", "8");
define_macro("__SIZEOF_LONG_LONG__", "8");
define_macro("__SIZEOF_LONG__", "8");
define_macro("__SIZEOF_POINTER__", "8");
define_macro("__SIZEOF_PTRDIFF_T__", "8");
define_macro("__SIZEOF_SHORT__", "2");
define_macro("__SIZEOF_SIZE_T__", "8");
define_macro("__SIZE_TYPE__", "unsigned long");
define_macro("__STDC_HOSTED__", "1");
define_macro("__STDC_NO_COMPLEX__", "1");
define_macro("__STDC_UTF_16__", "1");
define_macro("__STDC_UTF_32__", "1");
define_macro("__STDC_VERSION__", "201112L");
define_macro("__STDC__", "1");
define_macro("__USER_LABEL_PREFIX__", "");
define_macro("__alignof__", "_Alignof");
define_macro("__amd64", "1");
define_macro("__amd64__", "1");
define_macro("__chibicc__", "1");
define_macro("__const__", "const");
define_macro("__gnu_linux__", "1");
define_macro("__inline__", "inline");
define_macro("__linux", "1");
define_macro("__linux__", "1");
define_macro("__signed__", "signed");
define_macro("__typeof__", "typeof");
define_macro("__unix", "1");
define_macro("__unix__", "1");
define_macro("__volatile__", "volatile");
define_macro("__x86_64", "1");
define_macro("__x86_64__", "1");
define_macro("linux", "1");
define_macro("unix", "1");
char *val, *name = "\
__chibicc__\000\
1\000\
__cosmopolitan__\000\
1\000\
__GNUC__\000\
6\000\
__GNUC_MINOR__\000\
6\000\
__GNUC_PATCHLEVEL__\000\
6\000\
__NO_INLINE__\000\
16\000\
__BIGGEST_ALIGNMENT__\000\
16\000\
__C99_MACRO_WITH_VA_ARGS\000\
1\000\
__GCC_ASM_FLAG_OUTPUTS__\000\
1\000\
__ELF__\000\
1\000\
__LP64__\000\
1\000\
_LP64\000\
1\000\
__STDC__\000\
1\000\
__STDC_HOSTED__\000\
1\000\
__STDC_NO_COMPLEX__\000\
1\000\
__STDC_UTF_16__\000\
1\000\
__STDC_UTF_32__\000\
1\000\
__STDC_VERSION__\000\
201112L\000\
__USER_LABEL_PREFIX__\000\
\000\
__alignof__\000\
_Alignof\000\
__const__\000\
const\000\
__inline__\000\
inline\000\
__signed__\000\
signed\000\
__typeof__\000\
typeof\000\
__volatile__\000\
volatile\000\
__unix\000\
1\000\
__unix__\000\
1\000\
__linux\000\
1\000\
__linux__\000\
1\000\
__gnu_linux__\000\
1\000\
__BYTE_ORDER__\000\
1234\000\
__FLOAT_WORD_ORDER__\000\
1234\000\
__ORDER_BIG_ENDIAN__\000\
4321\000\
__ORDER_LITTLE_ENDIAN__\000\
1234\000\
__INT8_MAX__\000\
0x7f\000\
__UINT8_MAX__\000\
0xff\000\
__INT16_MAX__\000\
0x7fff\000\
__UINT16_MAX__\000\
0xffff\000\
__SHRT_MAX__\000\
0x7fff\000\
__INT_MAX__\000\
0x7fffffff\000\
__INT32_MAX__\000\
0x7fffffff\000\
__UINT32_MAX__\000\
0xffffffffu\000\
__INT64_MAX__\000\
0x7fffffffffffffffl\000\
__UINT64_MAX__\000\
0xfffffffffffffffful\000\
__SIZE_MAX__\000\
0xfffffffffffffffful\000\
__INTPTR_MAX__\000\
0x7fffffffffffffffl\000\
__UINTPTR_MAX__\000\
0xfffffffffffffffful\000\
__WINT_MAX__\000\
0xffffffffu\000\
__CHAR_BIT__\000\
8\000\
__SIZEOF_SHORT__\000\
2\000\
__SIZEOF_INT__\000\
4\000\
__SIZEOF_LONG__\000\
8\000\
__SIZEOF_LONG_LONG__\000\
8\000\
__SIZEOF_POINTER__\000\
8\000\
__SIZEOF_PTRDIFF_T__\000\
8\000\
__SIZEOF_SIZE_T__\000\
8\000\
__SIZEOF_WCHAR_T__\000\
4\000\
__SIZEOF_WINT_T__\000\
4\000\
__SIZEOF_FLOAT__\000\
4\000\
__SIZEOF_FLOAT128__\000\
16\000\
__SIZEOF_DOUBLE__\000\
8\000\
__SIZEOF_FLOAT80__\000\
16\000\
__SIZEOF_LONG_DOUBLE__\000\
16\000\
__INT8_TYPE__\000\
signed char\000\
__UINT8_TYPE__\000\
unsigned char\000\
__INT16_TYPE__\000\
short int\000\
__UINT16_TYPE__\000\
short unsigned int\000\
__INT32_TYPE__\000\
int\000\
__UINT32_TYPE__\000\
unsigned int\000\
__INT64_TYPE__\000\
long int\000\
__UINT64_TYPE__\000\
long unsigned int\000\
__INTPTR_TYPE__\000\
long int\000\
__UINTPTR_TYPE__\000\
long unsigned int\000\
__PTRDIFF_TYPE__\000\
long int\000\
__SIZE_TYPE__\000\
long unsigned int\000\
__WCHAR_TYPE__\000\
int\000\
__CHAR16_TYPE__\000\
short unsigned int\000\
__CHAR32_TYPE__\000\
unsigned int\000\
__WINT_TYPE__\000\
unsigned int\000\
__CHAR16_TYPE__\000\
short unsigned int\000\
__WCHAR_TYPE__\000\
int\000\
__CHAR32_TYPE__\000\
unsigned int\000\
__INT_LEAST8_TYPE__\000\
signed char\000\
__UINT_LEAST8_TYPE__\000\
unsigned char\000\
__INT_LEAST16_TYPE__\000\
int\000\
__UINT_LEAST16_TYPE__\000\
unsigned short\000\
__INT_LEAST32_TYPE__\000\
short\000\
__UINT_LEAST32_TYPE__\000\
unsigned int\000\
__INT_LEAST64_TYPE__\000\
long\000\
__UINT_LEAST64_TYPE__\000\
unsigned long\000\
__INT_FAST8_TYPE__\000\
signed char\000\
__UINT_FAST8_TYPE__\000\
unsigned char\000\
__INT_FAST16_TYPE__\000\
int\000\
__UINT_FAST16_TYPE__\000\
unsigned\000\
__INT_FAST32_TYPE__\000\
int\000\
__UINT_FAST32_TYPE__\000\
unsigned\000\
__INT_FAST64_TYPE__\000\
long\000\
__UINT_FAST64_TYPE__\000\
unsigned long\000\
__DBL_DECIMAL_DIG__\000\
17\000\
__DBL_DENORM_MIN__\000\
((double)4.94065645841246544176568792868221372e-324L)\000\
__DBL_DIG__\000\
15\000\
__DBL_EPSILON__\000\
((double)2.22044604925031308084726333618164062e-16L)\000\
__DBL_HAS_DENORM__\000\
1\000\
__DBL_HAS_INFINITY__\000\
1\000\
__DBL_HAS_QUIET_NAN__\000\
1\000\
__DBL_MANT_DIG__\000\
53\000\
__DBL_MAX_10_EXP__\000\
308\000\
__DBL_MAX_EXP__\000\
1024\000\
__DBL_MAX__\000\
((double)1.79769313486231570814527423731704357e+308L)\000\
__DBL_MIN_10_EXP__\000\
(-307)\000\
__DBL_MIN_EXP__\000\
(-1021)\000\
__DBL_MIN__\000\
((double)2.22507385850720138309023271733240406e-308L)\000\
__FLT_DECIMAL_DIG__\000\
9\000\
__FLT_DENORM_MIN__\000\
1.40129846432481707092372958328991613e-45F\000\
__FLT_DIG__\000\
6\000\
__FLT_EPSILON__\000\
1.19209289550781250000000000000000000e-7F\000\
__FLT_EVAL_METHOD_TS_18661_3__\000\
0\000\
__FLT_EVAL_METHOD__\000\
0\000\
__FLT_HAS_DENORM__\000\
1\000\
__FLT_HAS_INFINITY__\000\
1\000\
__FLT_HAS_QUIET_NAN__\000\
1\000\
__FLT_MANT_DIG__\000\
24\000\
__FLT_MAX_10_EXP__\000\
38\000\
__FLT_MAX_EXP__\000\
128\000\
__FLT_MAX__\000\
3.40282346638528859811704183484516925e+38F\000\
__FLT_MIN_10_EXP__\000\
(-37)\000\
__FLT_MIN_EXP__\000\
(-125)\000\
__FLT_MIN__\000\
1.17549435082228750796873653722224568e-38F\000\
__FLT_RADIX__\000\
2\000\
__LDBL_DECIMAL_DIG__\000\
21\000\
__LDBL_DENORM_MIN__\000\
3.64519953188247460252840593361941982e-4951L\000\
__LDBL_DIG__\000\
18\000\
__LDBL_EPSILON__\000\
1.08420217248550443400745280086994171e-19L\000\
__LDBL_HAS_DENORM__\000\
1\000\
__LDBL_HAS_INFINITY__\000\
1\000\
__LDBL_HAS_QUIET_NAN__\000\
1\000\
__LDBL_MANT_DIG__\000\
64\000\
__LDBL_MAX_10_EXP__\000\
4932\000\
__LDBL_MAX_EXP__\000\
16384\000\
__LDBL_MAX__\000\
1.18973149535723176502126385303097021e+4932L\000\
__LDBL_MIN_10_EXP__\000\
(-4931)\000\
__LDBL_MIN_EXP__\000\
(-16381)\000\
__LDBL_MIN__\000\
3.36210314311209350626267781732175260e-4932L\000\
__x86_64\000\
1\000\
__x86_64__\000\
1\000\
__amd64\000\
1\000\
__amd64__\000\
1\000\
__MMX__\000\
1\000\
__SSE__\000\
1\000\
__SSE_MATH__\000\
1\000\
__SSE2__\000\
1\000\
__SSE2_MATH__\000\
1\000\
\000";
do {
val = name + strlen(name) + 1;
define_macro(name, val);
name = val + strlen(val) + 1;
} while (*name);
#ifdef __SSE3__
define_macro("__SSE3__", "1");
#endif
add_builtin("__FILE__", file_macro);
add_builtin("__LINE__", line_macro);
add_builtin("__COUNTER__", counter_macro);
@ -1015,14 +1251,6 @@ void init_macros(void) {
define_macro("__TIME__", format_time(tm));
}
typedef enum {
STR_NONE,
STR_UTF8,
STR_UTF16,
STR_UTF32,
STR_WIDE,
} StringKind;
static StringKind getStringKind(Token *tok) {
if (!strcmp(tok->loc, "u8")) return STR_UTF8;
switch (tok->loc[0]) {
@ -1090,10 +1318,13 @@ static void join_adjacent_string_literals(Token *tok) {
// Entry point function of the preprocessor.
Token *preprocess(Token *tok) {
tok = preprocess2(tok);
if (cond_incl)
if (cond_incl) {
error_tok(cond_incl->tok, "unterminated conditional directive");
}
convert_pp_tokens(tok);
join_adjacent_string_literals(tok);
for (Token *t = tok; t; t = t->next) t->line_no += t->line_delta;
for (Token *t = tok; t; t = t->next) {
t->line_no += t->line_delta;
}
return tok;
}

View file

@ -5,12 +5,10 @@ void strarray_push(StringArray *arr, char *s) {
arr->data = calloc(8, sizeof(char *));
arr->capacity = 8;
}
if (arr->capacity == arr->len) {
arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
arr->capacity *= 2;
for (int i = arr->len; i < arr->capacity; i++) arr->data[i] = NULL;
}
arr->data[arr->len++] = s;
}

103
third_party/chibicc/test/alignof_test.c vendored Normal file
View file

@ -0,0 +1,103 @@
#include "third_party/chibicc/test/test.h"
int _Alignas(512) g1;
int _Alignas(512) g2;
char g3;
int g4;
long g5;
char g6;
int main() {
ASSERT(1, _Alignof(char));
ASSERT(2, _Alignof(short));
ASSERT(4, _Alignof(int));
ASSERT(8, _Alignof(long));
ASSERT(8, _Alignof(long long));
ASSERT(1, _Alignof(char[3]));
ASSERT(4, _Alignof(int[3]));
ASSERT(1, _Alignof(struct {
char a;
char b;
}[2]));
ASSERT(8, _Alignof(struct {
char a;
long b;
}[2]));
ASSERT(1, ({
_Alignas(char) char x, y;
&y - &x;
}));
ASSERT(8, ({
_Alignas(long) char x, y;
&y - &x;
}));
ASSERT(32, ({
_Alignas(32) char x, y;
&y - &x;
}));
ASSERT(32, ({
_Alignas(32) int *x, *y;
((char *)&y) - ((char *)&x);
}));
ASSERT(16, ({
struct {
_Alignas(16) char x, y;
} a;
&a.y - &a.x;
}));
ASSERT(8, ({
struct T {
_Alignas(8) char a;
};
_Alignof(struct T);
}));
ASSERT(0, (long)(char *)&g1 % 512);
ASSERT(0, (long)(char *)&g2 % 512);
ASSERT(0, (long)(char *)&g4 % 4);
ASSERT(0, (long)(char *)&g5 % 8);
ASSERT(1, ({
char x;
_Alignof(x);
}));
ASSERT(4, ({
int x;
_Alignof(x);
}));
ASSERT(1, ({
char x;
_Alignof x;
}));
ASSERT(4, ({
int x;
_Alignof x;
}));
ASSERT(1, _Alignof(char) << 31 >> 31);
ASSERT(1, _Alignof(char) << 63 >> 63);
ASSERT(1, ({
char x;
_Alignof(x) << 63 >> 63;
}));
ASSERT(0, ({
char x[16];
(unsigned long)&x % 16;
}));
ASSERT(0, ({
char x[17];
(unsigned long)&x % 16;
}));
ASSERT(0, ({
char x[100];
(unsigned long)&x % 16;
}));
ASSERT(0, ({
char x[101];
(unsigned long)&x % 16;
}));
return 0;
}

29
third_party/chibicc/test/alloca_test.c vendored Normal file
View file

@ -0,0 +1,29 @@
#include "third_party/chibicc/test/test.h"
void *fn(int x, void *p, int y) {
return p;
}
int main() {
int i = 0;
char *p1 = alloca(16);
char *p2 = alloca(16);
char *p3 = 1 + (char *)alloca(3) + 1;
p3 -= 2;
char *p4 = fn(1, alloca(16), 3);
ASSERT(16, p1 - p2);
ASSERT(16, p2 - p3);
ASSERT(16, p3 - p4);
memcpy(p1, "0123456789abcdef", 16);
memcpy(p2, "ghijklmnopqrstuv", 16);
memcpy(p3, "wxy", 3);
ASSERT(0, memcmp(p1, "0123456789abcdef", 16));
ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16));
ASSERT(0, memcmp(p3, "wxy", 3));
return 0;
}

341
third_party/chibicc/test/arith_test.c vendored Normal file
View file

@ -0,0 +1,341 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(0, 0);
ASSERT(42, 42);
ASSERT(21, 5 + 20 - 4);
ASSERT(41, 12 + 34 - 5);
ASSERT(47, 5 + 6 * 7);
ASSERT(15, 5 * (9 - 6));
ASSERT(4, (3 + 5) / 2);
ASSERT(10, -10 + 20);
ASSERT(0, 0 == 1);
ASSERT(1, 42 == 42);
ASSERT(1, 0 != 1);
ASSERT(0, 42 != 42);
ASSERT(1, 0 < 1);
ASSERT(0, 1 < 1);
ASSERT(0, 2 < 1);
ASSERT(1, 0 <= 1);
ASSERT(1, 1 <= 1);
ASSERT(0, 2 <= 1);
ASSERT(1, 1 > 0);
ASSERT(0, 1 > 1);
ASSERT(0, 1 > 2);
ASSERT(1, 1 >= 0);
ASSERT(1, 1 >= 1);
ASSERT(0, 1 >= 2);
ASSERT(0, 1073741824 * 100 / 100);
ASSERT(7, ({
int i = 2;
i += 5;
i;
}));
ASSERT(7, ({
int i = 2;
i += 5;
}));
ASSERT(3, ({
int i = 5;
i -= 2;
i;
}));
ASSERT(3, ({
int i = 5;
i -= 2;
}));
ASSERT(6, ({
int i = 3;
i *= 2;
i;
}));
ASSERT(6, ({
int i = 3;
i *= 2;
}));
ASSERT(3, ({
int i = 6;
i /= 2;
i;
}));
ASSERT(3, ({
int i = 6;
i /= 2;
}));
ASSERT(3, ({
int i = 2;
++i;
}));
ASSERT(2, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
++*p;
}));
ASSERT(0, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
--*p;
}));
ASSERT(2, ({
int i = 2;
i++;
}));
ASSERT(2, ({
int i = 2;
i--;
}));
ASSERT(3, ({
int i = 2;
i++;
i;
}));
ASSERT(1, ({
int i = 2;
i--;
i;
}));
ASSERT(1, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
*p++;
}));
ASSERT(1, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
*p--;
}));
ASSERT(0, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p++)--;
a[0];
}));
ASSERT(0, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*(p--))--;
a[1];
}));
ASSERT(2, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p)--;
a[2];
}));
ASSERT(2, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p)--;
p++;
*p;
}));
ASSERT(0, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p++)--;
a[0];
}));
ASSERT(0, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p++)--;
a[1];
}));
ASSERT(2, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p++)--;
a[2];
}));
ASSERT(2, ({
int a[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int *p = a + 1;
(*p++)--;
*p;
}));
ASSERT(0, !1);
ASSERT(0, !2);
ASSERT(1, !0);
ASSERT(1, !(char)0);
ASSERT(0, !(long)3);
ASSERT(4, sizeof(!(char)0));
ASSERT(4, sizeof(!(long)0));
ASSERT(-1, ~0);
ASSERT(0, ~-1);
ASSERT(5, 17 % 6);
ASSERT(5, ((long)17) % 6);
ASSERT(2, ({
int i = 10;
i %= 4;
i;
}));
ASSERT(2, ({
long i = 10;
i %= 4;
i;
}));
ASSERT(0, 0 & 1);
ASSERT(1, 3 & 1);
ASSERT(3, 7 & 3);
ASSERT(10, -1 & 10);
ASSERT(1, 0 | 1);
ASSERT(0b10011, 0b10000 | 0b00011);
ASSERT(0, 0 ^ 0);
ASSERT(0, 0b1111 ^ 0b1111);
ASSERT(0b110100, 0b111000 ^ 0b001100);
ASSERT(2, ({
int i = 6;
i &= 3;
i;
}));
ASSERT(7, ({
int i = 6;
i |= 3;
i;
}));
ASSERT(10, ({
int i = 15;
i ^= 5;
i;
}));
ASSERT(1, 1 << 0);
ASSERT(8, 1 << 3);
ASSERT(10, 5 << 1);
ASSERT(2, 5 >> 1);
ASSERT(-1, -1 >> 1);
ASSERT(1, ({
int i = 1;
i <<= 0;
i;
}));
ASSERT(8, ({
int i = 1;
i <<= 3;
i;
}));
ASSERT(10, ({
int i = 5;
i <<= 1;
i;
}));
ASSERT(2, ({
int i = 5;
i >>= 1;
i;
}));
ASSERT(-1, -1);
ASSERT(-1, ({
int i = -1;
i;
}));
ASSERT(-1, ({
int i = -1;
i >>= 1;
i;
}));
ASSERT(2, 0 ? 1 : 2);
ASSERT(1, 1 ? 1 : 2);
ASSERT(-1, 0 ? -2 : -1);
ASSERT(-2, 1 ? -2 : -1);
ASSERT(4, sizeof(0 ? 1 : 2));
ASSERT(8, sizeof(0 ? (long)1 : (long)2));
ASSERT(-1, 0 ? (long)-2 : -1);
ASSERT(-1, 0 ? -2 : (long)-1);
ASSERT(-2, 1 ? (long)-2 : -1);
ASSERT(-2, 1 ? -2 : (long)-1);
1 ? -2 : (void)-1;
ASSERT(20, ({
int x;
int *p = &x;
p + 20 - p;
}));
ASSERT(1, ({
int x;
int *p = &x;
p + 20 - p > 0;
}));
ASSERT(-20, ({
int x;
int *p = &x;
p - 20 - p;
}));
ASSERT(1, ({
int x;
int *p = &x;
p - 20 - p < 0;
}));
ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0);
ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff);
ASSERT(1, (void *)0xffffffffffffffff > (void *)0);
ASSERT(3, 3 ?: 5);
ASSERT(5, 0 ?: 5);
ASSERT(4, ({
int i = 3;
++i ?: 10;
}));
ASSERT(3, (long double)3);
ASSERT(5, (long double)3 + 2);
ASSERT(6, (long double)3 * 2);
ASSERT(5, (long double)3 + 2.0);
return 0;
}

132
third_party/chibicc/test/asm_test.c vendored Normal file
View file

@ -0,0 +1,132 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "third_party/chibicc/test/test.h"
char *asm_fn1(void) {
asm("mov\t$50,%rax\n\t"
"mov\t%rbp,%rsp\n\t"
"leave\n\t"
"ret");
}
char *asm_fn2(void) {
asm inline volatile("mov\t$55,%rax\n\t"
"mov\t%rbp,%rsp\n\t"
"leave\n\t"
"ret");
}
void *repmovsb(void *dst, void *src, unsigned long n) {
asm("rep movsb"
: "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst)
: "0"(dst), "1"(src), "2"(n), "m"(*(const char(*)[n])src));
return dst;
}
void *repmovsbeax(void *dst, void *src, unsigned long n) {
void *res;
asm("rep movsb\n\t"
"xchg\t%0,%1"
: "=a"(res), "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst)
: "1"(dst), "2"(src), "3"(n), "m"(*(const char(*)[n])src)
: "rbx", "rbp", "r12", "r13", "r14", "r15", "cc");
return res;
}
void testSmashStackFrame_clobberIsRestored(void) {
asm volatile("xor\t%%ebp,%%ebp"
: /* no outputs */
: /* no inputs */
: "rbp", "cc");
}
void testFlagOutputs(void) {
bool zf, cf, sf;
asm("xor\t%%eax,%%eax\n\t"
"inc\t%%eax"
: "=@ccz"(zf), "=@ccs"(cf)
: /* no inputs */
: "rax");
ASSERT(false, zf);
ASSERT(false, sf);
asm("xor\t%%eax,%%eax\n\t"
"dec\t%%eax"
: "=@ccz"(zf), "=@ccs"(cf)
: /* no inputs */
: "rax");
ASSERT(false, zf);
ASSERT(true, sf);
asm("xor\t%%eax,%%eax\n\t"
"cmc"
: "=@ccz"(zf), "=@ccc"(cf), "=@ccs"(sf)
: /* no inputs */
: "rax");
ASSERT(true, zf);
ASSERT(true, cf);
ASSERT(false, sf);
}
int main() {
ASSERT(50, asm_fn1());
ASSERT(55, asm_fn2());
{
char buf[] = "HELLO";
char *s = "hello";
char *p = repmovsb(buf, s, 4);
ASSERT(4, p - buf);
ASSERT('h', buf[0]);
ASSERT('e', buf[1]);
ASSERT('l', buf[2]);
ASSERT('l', buf[3]);
ASSERT('O', buf[4]);
}
{
char buf[] = "HELLO";
char *s = "hello";
char *p = repmovsbeax(buf, s, 4);
ASSERT(4, p - buf);
ASSERT('h', buf[0]);
ASSERT('e', buf[1]);
ASSERT('l', buf[2]);
ASSERT('l', buf[3]);
ASSERT('O', buf[4]);
}
testSmashStackFrame_clobberIsRestored();
short v1[8] = {0, 1, 2, 3, 4, 5, 6, 7};
short v2[8] = {1, 1, 1, 1, 1, 1, 1, 1};
short v3[8] = {2, 2, 2, 2, 2, 2, 2, 2};
asm("paddsw\t%1,%0\n\t"
"paddsw\t%2,%0"
: "+x"(v1)
: "xm"(v2), "xm"(v3));
ASSERT(3, v1[0]);
ASSERT(4, v1[1]);
ASSERT(5, v1[2]);
ASSERT(6, v1[3]);
ASSERT(7, v1[4]);
ASSERT(8, v1[5]);
ASSERT(9, v1[6]);
ASSERT(10, v1[7]);
return 0;
}

View file

@ -0,0 +1,160 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(5, ({
struct {
char a;
int b;
} __attribute__((packed)) x;
sizeof(x);
}));
ASSERT(0, offsetof(
struct __attribute__((packed)) {
char a;
int b;
},
a));
ASSERT(1, offsetof(
struct __attribute__((packed)) {
char a;
int b;
},
b));
ASSERT(5, ({
struct __attribute__((packed)) {
char a;
int b;
} x;
sizeof(x);
}));
ASSERT(0, offsetof(
struct {
char a;
int b;
} __attribute__((packed)),
a));
ASSERT(1, offsetof(
struct {
char a;
int b;
} __attribute__((packed)),
b));
ASSERT(9, ({
typedef struct {
char a;
int b[2];
} __attribute__((packed)) T;
sizeof(T);
}));
ASSERT(9, ({
typedef struct __attribute__((packed)) {
char a;
int b[2];
} T;
sizeof(T);
}));
ASSERT(1, offsetof(
struct __attribute__((packed)) T {
char a;
int b[2];
},
b));
ASSERT(1, _Alignof(struct __attribute__((packed)) {
char a;
int b[2];
}));
ASSERT(8, ({
struct __attribute__((aligned(8))) {
int a;
} x;
_Alignof(x);
}));
ASSERT(8, ({
struct {
int a;
} __attribute__((aligned(8))) x;
_Alignof(x);
}));
ASSERT(8, ({
struct __attribute__((aligned(8), packed)) {
char a;
int b;
} x;
_Alignof(x);
}));
ASSERT(8, ({
struct {
char a;
int b;
} __attribute__((aligned(8), packed)) x;
_Alignof(x);
}));
ASSERT(1, offsetof(
struct __attribute__((aligned(8), packed)) {
char a;
int b;
},
b));
ASSERT(1, offsetof(
struct {
char a;
int b;
} __attribute__((aligned(8), packed)),
b));
ASSERT(8, ({
struct __attribute__((aligned(8))) __attribute__((packed)) {
char a;
int b;
} x;
_Alignof(x);
}));
ASSERT(8, ({
struct {
char a;
int b;
} __attribute__((aligned(8))) __attribute__((packed)) x;
_Alignof(x);
}));
ASSERT(1, offsetof(
struct __attribute__((aligned(8))) __attribute__((packed)) {
char a;
int b;
},
b));
ASSERT(1, offsetof(
struct {
char a;
int b;
} __attribute__((aligned(8))) __attribute__((packed)),
b));
ASSERT(8, ({
struct __attribute__((aligned(8))) {
char a;
int b;
} __attribute__((packed)) x;
_Alignof(x);
}));
ASSERT(1, offsetof(
struct __attribute__((aligned(8))) {
char a;
int b;
} __attribute__((packed)),
b));
ASSERT(16, ({
struct __attribute__((aligned(8 + 8))) {
char a;
int b;
} x;
_Alignof(x);
}));
return 0;
}

128
third_party/chibicc/test/bitfield_test.c vendored Normal file
View file

@ -0,0 +1,128 @@
#include "third_party/chibicc/test/test.h"
struct {
char a;
int b : 5;
int c : 10;
} g45 = {1, 2, 3}, g46 = {};
int main() {
ASSERT(4, sizeof(struct { int x : 1; }));
ASSERT(8, sizeof(struct { long x : 1; }));
struct bit1 {
short a;
char b;
int c : 2;
int d : 3;
int e : 3;
};
ASSERT(4, sizeof(struct bit1));
ASSERT(1, ({
struct bit1 x;
x.a = 1;
x.b = 2;
x.c = 3;
x.d = 4;
x.e = 5;
x.a;
}));
ASSERT(1, ({
struct bit1 x = {1, 2, 3, 4, 5};
x.a;
}));
ASSERT(2, ({
struct bit1 x = {1, 2, 3, 4, 5};
x.b;
}));
ASSERT(-1, ({
struct bit1 x = {1, 2, 3, 4, 5};
x.c;
}));
ASSERT(-4, ({
struct bit1 x = {1, 2, 3, 4, 5};
x.d;
}));
ASSERT(-3, ({
struct bit1 x = {1, 2, 3, 4, 5};
x.e;
}));
ASSERT(1, g45.a);
ASSERT(2, g45.b);
ASSERT(3, g45.c);
ASSERT(0, g46.a);
ASSERT(0, g46.b);
ASSERT(0, g46.c);
typedef struct {
int a : 10;
int b : 10;
int c : 10;
} T3;
ASSERT(1, ({
T3 x = {1, 2, 3};
x.a++;
}));
ASSERT(2, ({
T3 x = {1, 2, 3};
x.b++;
}));
ASSERT(3, ({
T3 x = {1, 2, 3};
x.c++;
}));
ASSERT(2, ({
T3 x = {1, 2, 3};
++x.a;
}));
ASSERT(3, ({
T3 x = {1, 2, 3};
++x.b;
}));
ASSERT(4, ({
T3 x = {1, 2, 3};
++x.c;
}));
ASSERT(4, sizeof(struct {
int a : 3;
int c : 1;
int c : 5;
}));
ASSERT(8, sizeof(struct {
int a : 3;
int : 0;
int c : 5;
}));
ASSERT(4, sizeof(struct {
int a : 3;
int : 0;
}));
typedef struct {
long p : 1;
long a : 40;
long b : 20;
} T4;
ASSERT(0xfffffffffffaaaaa, ({
T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa};
x.b++;
}));
ASSERT(0x7313371337, ({
T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa};
x.a++;
}));
ASSERT(0xffffffffffffffd4, ({
T4 x;
x.b = -44;
x.b++;
}));
return 0;
}

242
third_party/chibicc/test/builtin_test.c vendored Normal file
View file

@ -0,0 +1,242 @@
#include "third_party/chibicc/test/test.h"
#define FPNAN 0
#define FPINFINITE 1
#define FPZERO 2
#define FPSUBNORMAL 3
#define FPNORMAL 4
#define FPCLASSIFY(x) \
__builtin_fpclassify(FPNAN, FPINFINITE, FPNORMAL, FPSUBNORMAL, FPZERO, x)
void test_constant(void) {
ASSERT(1, __builtin_constant_p(1));
ASSERT(0, __builtin_constant_p(stdin));
ASSERT(1, __builtin_constant_p(__builtin_popcount(0b10111011)));
}
void test_fpclassify(void) {
float minf = __FLT_MIN__;
double min = __DBL_MIN__;
long double minl = __LDBL_MIN__;
ASSERT(FPZERO, FPCLASSIFY(.0f));
ASSERT(FPZERO, FPCLASSIFY(.0));
ASSERT(FPZERO, FPCLASSIFY(.0L));
ASSERT(FPNORMAL, FPCLASSIFY(1.f));
ASSERT(FPNORMAL, FPCLASSIFY(1.));
ASSERT(FPNORMAL, FPCLASSIFY(1.L));
ASSERT(FPNORMAL, FPCLASSIFY(1.f));
ASSERT(FPNORMAL, FPCLASSIFY(1.));
ASSERT(FPNORMAL, FPCLASSIFY(1.L));
ASSERT(FPNORMAL, FPCLASSIFY(minf));
ASSERT(FPNORMAL, FPCLASSIFY(min));
ASSERT(FPNORMAL, FPCLASSIFY(minl));
ASSERT(FPSUBNORMAL, FPCLASSIFY(minf / 2));
ASSERT(FPSUBNORMAL, FPCLASSIFY(min / 2));
ASSERT(FPSUBNORMAL, FPCLASSIFY(minl / 2));
ASSERT(FPNAN, FPCLASSIFY(__builtin_nanf("")));
ASSERT(FPNAN, FPCLASSIFY(__builtin_nan("")));
ASSERT(FPNAN, FPCLASSIFY(__builtin_nanl("")));
}
void __attribute__((__aligned__(16))) test_clz(void) {
ASSERT(31, __builtin_clz(1));
ASSERT(63, __builtin_clzl(1));
ASSERT(63, __builtin_clzll(1));
ASSERT(25, __builtin_clz(77));
ASSERT(4, __builtin_clz(0x08000000));
ASSERT(4, __builtin_clz(0xfff08000000));
}
__attribute__((__weak__)) void test_ctz(void) {
ASSERT(0, __builtin_ctz(1));
ASSERT(0, __builtin_ctz(77));
ASSERT(27, __builtin_ctz(0x08000000));
ASSERT(27, __builtin_ctz(0xffff08000000));
ASSERT(63, __builtin_ctzl(0x8000000000000000));
ASSERT(63, __builtin_ctzll(0x8000000000000000));
}
void test_ffs(void) {
ASSERT(0, __builtin_ffs(0));
ASSERT(1, __builtin_ffs(1));
ASSERT(1, __builtin_ffs(77));
ASSERT(28, __builtin_ffs(0x08000000));
ASSERT(28, __builtin_ffs(0xffff08000000));
}
void test_popcnt(void) {
ASSERT(0, __builtin_popcount(0));
ASSERT(1, __builtin_popcount(1));
ASSERT(6, __builtin_popcount(0b10111011));
ASSERT(6, __builtin_popcountl(0b10111011));
ASSERT(6, __builtin_popcountll(0xbb00000000000000));
}
void test_bswap(void) {
ASSERT(0x3412, __builtin_bswap16(0x1234));
ASSERT(0x78563412, __builtin_bswap32(0x12345678));
ASSERT(0xefcdab8967452301, __builtin_bswap64(0x0123456789abcdef));
ASSERT(0xefcdab89, __builtin_bswap32(0x0123456789abcdef));
}
void test_memcpy(void) {
{
char x[5] = {4, 3, 2, 1, 0};
char y[5] = {0, 1, 2, 3, 4};
char z[5] = {2, 3, 4, 1, 0};
ASSERT(1, x == __builtin_memcpy(x, y + 2, 3));
ASSERT(0, memcmp(x, z, 5));
}
{
int n = 3;
char x[5] = {4, 3, 2, 1, 0};
char y[5] = {0, 1, 2, 3, 4};
char z[5] = {2, 3, 4, 1, 0};
ASSERT(1, x == __builtin_memcpy(x, y + 2, n));
ASSERT(0, memcmp(x, z, 5));
}
}
void test_inf(void) {
ASSERT(0, __builtin_isinf(0));
ASSERT(0, __builtin_isinf(1));
ASSERT(1, __builtin_isinf(__builtin_inff()));
ASSERT(1, __builtin_isinf(-__builtin_inff()));
ASSERT(1, __builtin_isinf(__builtin_inf()));
ASSERT(1, __builtin_isinf(-__builtin_inf()));
ASSERT(1, __builtin_isinf(__builtin_infl()));
ASSERT(1, __builtin_isinf(-__builtin_infl()));
ASSERT(1, __builtin_isfinite(0));
ASSERT(1, __builtin_isfinite(1));
ASSERT(0, __builtin_isfinite(__builtin_inff()));
ASSERT(0, __builtin_isfinite(-__builtin_inff()));
ASSERT(0, __builtin_isfinite(__builtin_inf()));
ASSERT(0, __builtin_isfinite(-__builtin_inf()));
ASSERT(0, __builtin_isfinite(__builtin_infl()));
ASSERT(0, __builtin_isfinite(-__builtin_infl()));
}
void test_signbit(void) {
ASSERT(0, !!__builtin_signbitf(0));
ASSERT(0, !!__builtin_signbitf(0.f));
ASSERT(0, !!__builtin_signbit(0.));
ASSERT(0, !!__builtin_signbitl(0.L));
ASSERT(1, !!__builtin_signbitf(-0.f));
ASSERT(1, !!__builtin_signbit(-0.));
ASSERT(1, !!__builtin_signbitl(-0.L));
ASSERT(0, !!__builtin_signbitf(__builtin_nanf("")));
ASSERT(1, !!__builtin_signbitf(-__builtin_nanf("")));
ASSERT(0, !!__builtin_signbit(__builtin_nan("")));
ASSERT(1, !!__builtin_signbit(-__builtin_nan("")));
ASSERT(0, !!__builtin_signbitl(__builtin_nanl("")));
ASSERT(1, !!__builtin_signbitl(-__builtin_nanl("")));
ASSERT(0, !!__builtin_signbitf(__builtin_inff()));
ASSERT(1, !!__builtin_signbitf(-__builtin_inff()));
ASSERT(0, !!__builtin_signbit(__builtin_inf()));
ASSERT(1, !!__builtin_signbit(-__builtin_inf()));
ASSERT(0, !!__builtin_signbitl(__builtin_infl()));
ASSERT(1, !!__builtin_signbitl(-__builtin_infl()));
}
void test_nan(void) {
ASSERT(0, __builtin_isnan(0));
ASSERT(0, __builtin_isnan(1));
ASSERT(1, __builtin_isnan(__builtin_nanf("")));
ASSERT(1, __builtin_isnan(-__builtin_nanf("")));
ASSERT(1, __builtin_isnan(__builtin_nan("")));
ASSERT(1, __builtin_isnan(-__builtin_nan("")));
ASSERT(1, __builtin_isnan(__builtin_nanl("")));
ASSERT(1, __builtin_isnan(-__builtin_nanl("")));
ASSERT(0, __builtin_isunordered(0, 0));
ASSERT(0, __builtin_isunordered(-1, 1));
ASSERT(1, __builtin_isunordered(0, __builtin_nanf("")));
ASSERT(1, __builtin_isunordered(__builtin_nanf(""), 0));
ASSERT(1, __builtin_isunordered(__builtin_nanf(""), __builtin_nanf("")));
}
void test_double(void) { /* TODO */
/* ASSERT(1, __DBL_MIN__ < 0.0L); */
/* ASSERT(1, __DBL_MAX__ > 0.0L); */
}
void test_types_compatible_p(void) {
ASSERT(1, __builtin_types_compatible_p(int, int));
ASSERT(1, __builtin_types_compatible_p(double, double));
ASSERT(0, __builtin_types_compatible_p(int, long));
ASSERT(0, __builtin_types_compatible_p(long, float));
ASSERT(1, __builtin_types_compatible_p(int *, int *));
ASSERT(0, __builtin_types_compatible_p(short *, int *));
ASSERT(0, __builtin_types_compatible_p(int **, int *));
ASSERT(1, __builtin_types_compatible_p(const int, int));
ASSERT(0, __builtin_types_compatible_p(unsigned, int));
ASSERT(1, __builtin_types_compatible_p(signed, int));
ASSERT(0, __builtin_types_compatible_p(
struct { int a; }, struct { int a; }));
ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void)));
ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int)));
ASSERT(1, __builtin_types_compatible_p(void (*)(int, double),
void (*)(int, double)));
ASSERT(1, __builtin_types_compatible_p(int (*)(float, double),
int (*)(float, double)));
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int));
ASSERT(0,
__builtin_types_compatible_p(int (*)(float, double), int (*)(float)));
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double),
int (*)(float, double, int)));
ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...)));
ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void)));
ASSERT(1, ({
typedef struct {
int a;
} T;
__builtin_types_compatible_p(T, T);
}));
ASSERT(1, ({
typedef struct {
int a;
} T;
__builtin_types_compatible_p(T, const T);
}));
ASSERT(1, ({
struct {
int a;
int b;
} x;
__builtin_types_compatible_p(typeof(x.a), typeof(x.b));
}));
}
void test_offsetof(void) {
ASSERT(0, ({
struct T {
int a;
int b;
};
__builtin_offsetof(struct T, a);
}));
ASSERT(4, ({
struct T {
int a;
int b;
};
__builtin_offsetof(struct T, b);
}));
}
int main() {
test_constant();
test_types_compatible_p();
test_clz();
test_ctz();
test_ffs();
test_bswap();
test_popcnt();
test_inf();
test_nan();
test_double();
test_fpclassify();
test_signbit();
test_memcpy();
test_offsetof();
return 0;
}

80
third_party/chibicc/test/cast_test.c vendored Normal file
View file

@ -0,0 +1,80 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(131585, (int)8590066177);
ASSERT(513, (short)8590066177);
ASSERT(1, (char)8590066177);
ASSERT(1, (long)1);
ASSERT(0, (long)&*(int *)0);
ASSERT(513, ({
int x = 512;
*(char *)&x = 1;
x;
}));
ASSERT(5, ({
int x = 5;
long y = (long)&x;
*(int *)y;
}));
(void)1;
ASSERT(-1, (char)255);
ASSERT(-1, (signed char)255);
ASSERT(255, (unsigned char)255);
ASSERT(-1, (short)65535);
ASSERT(65535, (unsigned short)65535);
ASSERT(-1, (int)0xffffffff);
ASSERT(0xffffffff, (unsigned)0xffffffff);
ASSERT(1, -1 < 1);
ASSERT(0, -1 < (unsigned)1);
ASSERT(254, (char)127 + (char)127);
ASSERT(65534, (short)32767 + (short)32767);
ASSERT(-1, -1 >> 1);
ASSERT(-1, (unsigned long)-1);
ASSERT(2147483647, ((unsigned)-1) >> 1);
ASSERT(-50, (-100) / 2);
ASSERT(2147483598, ((unsigned)-100) / 2);
ASSERT(9223372036854775758, ((unsigned long)-100) / 2);
ASSERT(0, ((long)-1) / (unsigned)100);
ASSERT(-2, (-100) % 7);
ASSERT(2, ((unsigned)-100) % 7);
ASSERT(6, ((unsigned long)-100) % 9);
ASSERT(65535, (int)(unsigned short)65535);
ASSERT(65535, ({
unsigned short x = 65535;
x;
}));
ASSERT(65535, ({
unsigned short x = 65535;
(int)x;
}));
ASSERT(-1, ({
typedef short T;
T x = 65535;
(int)x;
}));
ASSERT(65535, ({
typedef unsigned short T;
T x = 65535;
(int)x;
}));
ASSERT(0, (_Bool)0.0);
ASSERT(1, (_Bool)0.1);
ASSERT(3, (char)3.0);
ASSERT(1000, (short)1000.3);
ASSERT(3, (int)3.99);
ASSERT(2000000000000000, (long)2e15);
ASSERT(3, (float)3.5);
ASSERT(5, (double)(float)5.5);
ASSERT(3, (float)3);
ASSERT(3, (double)3);
ASSERT(3, (float)3L);
ASSERT(3, (double)3L);
return 0;
}

195
third_party/chibicc/test/common.c vendored Normal file
View file

@ -0,0 +1,195 @@
#include "third_party/chibicc/test/test.h"
void Assert(long expected, long actual, char *code) {
if (expected != actual) {
fprintf(stderr, "%s => %ld expected but got %ld\n", code, expected, actual);
exit(1);
}
}
void Assert2(long expected, long actual, char *code, char *func, int line) {
if (expected != actual) {
fprintf(stderr, "%s:%d: %s => expected %ld but got %ld\n", func, line, code,
expected, actual);
exit(1);
}
}
void Assert128(__int128 k, __int128 x, char *code, char *func, int line) {
if (k != x) {
fprintf(stderr, "%s:%d: %s => want %jd but got %jd\n", func, line, code, k,
x);
exit(1);
}
}
static int static_fn() {
return 5;
}
int ext1 = 5;
int *ext2 = &ext1;
int ext3 = 7;
int ext_fn1(int x) {
return x;
}
int ext_fn2(int x) {
return x;
}
int common_ext2 = 3;
static int common_local;
int false_fn() {
return 512;
}
int true_fn() {
return 513;
}
int char_fn() {
return (2 << 8) + 3;
}
int short_fn() {
return (2 << 16) + 5;
}
int uchar_fn() {
return (2 << 10) - 1 - 4;
}
int ushort_fn() {
return (2 << 20) - 1 - 7;
}
int schar_fn() {
return (2 << 10) - 1 - 4;
}
int sshort_fn() {
return (2 << 20) - 1 - 7;
}
int add_all(int n, ...) {
va_list ap;
va_start(ap, n);
int sum = 0;
for (int i = 0; i < n; i++) sum += va_arg(ap, int);
va_end(ap);
return sum;
}
float add_float(float x, float y) {
return x + y;
}
double add_double(double x, double y) {
return x + y;
}
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8,
int x9, int x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6,
float x7, float x8, float x9, float x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
double add10_double(double x1, double x2, double x3, double x4, double x5,
double x6, double x7, double x8, double x9, double x10) {
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
}
typedef struct {
int a, b;
short c;
char d;
} Ty4;
typedef struct {
int a;
float b;
double c;
} Ty5;
typedef struct {
unsigned char a[3];
} Ty6;
typedef struct {
long a, b, c;
} Ty7;
int struct_test4(Ty4 x, int n) {
switch (n) {
case 0:
return x.a;
case 1:
return x.b;
case 2:
return x.c;
default:
return x.d;
}
}
int struct_test5(Ty5 x, int n) {
switch (n) {
case 0:
return x.a;
case 1:
return x.b;
default:
return x.c;
}
}
int struct_test6(Ty6 x, int n) {
return x.a[n];
}
int struct_test7(Ty7 x, int n) {
switch (n) {
case 0:
return x.a;
case 1:
return x.b;
default:
return x.c;
}
}
Ty4 struct_test24(void) {
return (Ty4){10, 20, 30, 40};
}
Ty5 struct_test25(void) {
return (Ty5){10, 20, 30};
}
Ty6 struct_test26(void) {
return (Ty6){{10, 20, 30}};
}
typedef struct {
unsigned char a[10];
} Ty20;
typedef struct {
unsigned char a[20];
} Ty21;
Ty20 struct_test27(void) {
return (Ty20){{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}};
}
Ty21 struct_test28(void) {
return (Ty21){
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}};
}

18
third_party/chibicc/test/compat_test.c vendored Normal file
View file

@ -0,0 +1,18 @@
#include "third_party/chibicc/test/test.h"
_Noreturn noreturn_fn(int restrict x) {
exit(0);
}
void funcy_type(int arg[restrict static 3]) {
}
int main() {
{ volatile x; }
{ int volatile x; }
{ volatile int x; }
{ volatile int volatile volatile x; }
{ int volatile *volatile volatile x; }
{ auto **restrict __restrict __restrict__ const volatile *x; }
return 0;
}

31
third_party/chibicc/test/complit_test.c vendored Normal file
View file

@ -0,0 +1,31 @@
#include "third_party/chibicc/test/test.h"
typedef struct Tree {
int val;
struct Tree *lhs;
struct Tree *rhs;
} Tree;
Tree *tree = &(Tree){1, &(Tree){2, &(Tree){3, 0, 0}, &(Tree){4, 0, 0}}, 0};
int main() {
ASSERT(1, (int){1});
ASSERT(2, ((int[]){0, 1, 2})[2]);
ASSERT('a', ((struct {
char a;
int b;
}){'a', 3})
.a);
ASSERT(3, ({
int x = 3;
(int){x};
}));
(int){3} = 5;
ASSERT(1, tree->val);
ASSERT(2, tree->lhs->val);
ASSERT(3, tree->lhs->lhs->val);
ASSERT(4, tree->lhs->rhs->val);
return 0;
}

23
third_party/chibicc/test/const_test.c vendored Normal file
View file

@ -0,0 +1,23 @@
#include "third_party/chibicc/test/test.h"
int main() {
{ const x; }
{ int const x; }
{ const int x; }
{ const int const const x; }
ASSERT(5, ({
const x = 5;
x;
}));
ASSERT(8, ({
const x = 8;
int *const y = &x;
*y;
}));
ASSERT(6, ({
const x = 6;
*(const *const) & x;
}));
return 0;
}

View file

@ -0,0 +1,181 @@
#include "third_party/chibicc/test/test.h"
float g40 = 1.5;
double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0);
int main() {
ASSERT(10, ({
enum { ten = 1 + 2 + 3 + 4 };
ten;
}));
ASSERT(1, ({
int i = 0;
switch (3) {
case 5 - 2 + 0 * 3:
i++;
}
i;
}));
ASSERT(8, ({
int x[1 + 1];
sizeof(x);
}));
ASSERT(6, ({
char x[8 - 2];
sizeof(x);
}));
ASSERT(6, ({
char x[2 * 3];
sizeof(x);
}));
ASSERT(3, ({
char x[12 / 4];
sizeof(x);
}));
ASSERT(2, ({
char x[12 % 10];
sizeof(x);
}));
ASSERT(0b100, ({
char x[0b110 & 0b101];
sizeof(x);
}));
ASSERT(0b111, ({
char x[0b110 | 0b101];
sizeof(x);
}));
ASSERT(0b110, ({
char x[0b111 ^ 0b001];
sizeof(x);
}));
ASSERT(4, ({
char x[1 << 2];
sizeof(x);
}));
ASSERT(2, ({
char x[4 >> 1];
sizeof(x);
}));
ASSERT(2, ({
char x[(1 == 1) + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[(1 != 1) + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[(1 < 1) + 1];
sizeof(x);
}));
ASSERT(2, ({
char x[(1 <= 1) + 1];
sizeof(x);
}));
ASSERT(2, ({
char x[1 ? 2 : 3];
sizeof(x);
}));
ASSERT(3, ({
char x[0 ? 2 : 3];
sizeof(x);
}));
ASSERT(3, ({
char x[(1, 3)];
sizeof(x);
}));
ASSERT(2, ({
char x[!0 + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[!1 + 1];
sizeof(x);
}));
ASSERT(2, ({
char x[~-3];
sizeof(x);
}));
ASSERT(2, ({
char x[(5 || 6) + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[(0 || 0) + 1];
sizeof(x);
}));
ASSERT(2, ({
char x[(1 && 1) + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[(1 && 0) + 1];
sizeof(x);
}));
ASSERT(3, ({
char x[(int)3];
sizeof(x);
}));
ASSERT(15, ({
char x[(char)0xffffff0f];
sizeof(x);
}));
ASSERT(0x10f, ({
char x[(short)0xffff010f];
sizeof(x);
}));
ASSERT(4, ({
char x[(int)0xfffffffffff + 5];
sizeof(x);
}));
ASSERT(8, ({
char x[(int*)0 + 2];
sizeof(x);
}));
ASSERT(12, ({
char x[(int*)16 - 1];
sizeof(x);
}));
ASSERT(3, ({
char x[(int*)16 - (int*)4];
sizeof(x);
}));
ASSERT(4, ({
char x[(-1 >> 31) + 5];
sizeof(x);
}));
ASSERT(255, ({
char x[(unsigned char)0xffffffff];
sizeof(x);
}));
ASSERT(0x800f, ({
char x[(unsigned short)0xffff800f];
sizeof(x);
}));
ASSERT(1, ({
char x[(unsigned int)0xfffffffffff >> 31];
sizeof(x);
}));
ASSERT(1, ({
char x[(long)-1 / ((long)1 << 62) + 1];
sizeof(x);
}));
ASSERT(4, ({
char x[(unsigned long)-1 / ((long)1 << 62) + 1];
sizeof(x);
}));
ASSERT(1, ({
char x[(unsigned)1 < -1];
sizeof(x);
}));
ASSERT(1, ({
char x[(unsigned)1 <= -1];
sizeof(x);
}));
ASSERT(1, g40 == 1.5);
ASSERT(1, g41 == 11);
return 0;
}

542
third_party/chibicc/test/control_test.c vendored Normal file
View file

@ -0,0 +1,542 @@
#include "third_party/chibicc/test/test.h"
/*
* This is a block comment.
*/
int main() {
ASSERT(3, ({
int x;
if (0)
x = 2;
else
x = 3;
x;
}));
ASSERT(3, ({
int x;
if (1 - 1)
x = 2;
else
x = 3;
x;
}));
ASSERT(2, ({
int x;
if (1)
x = 2;
else
x = 3;
x;
}));
ASSERT(2, ({
int x;
if (2 - 1)
x = 2;
else
x = 3;
x;
}));
ASSERT(55, ({
int i = 0;
int j = 0;
for (i = 0; i <= 10; i = i + 1) j = i + j;
j;
}));
ASSERT(10, ({
int i = 0;
while (i < 10) i = i + 1;
i;
}));
ASSERT(3, ({
1;
{ 2; }
3;
}));
ASSERT(5, ({
;
;
;
5;
}));
ASSERT(10, ({
int i = 0;
while (i < 10) i = i + 1;
i;
}));
ASSERT(55, ({
int i = 0;
int j = 0;
while (i <= 10) {
j = i + j;
i = i + 1;
}
j;
}));
ASSERT(3, (1, 2, 3));
ASSERT(5, ({
int i = 2, j = 3;
(i = 5, j) = 6;
i;
}));
ASSERT(6, ({
int i = 2, j = 3;
(i = 5, j) = 6;
j;
}));
ASSERT(55, ({
int j = 0;
for (int i = 0; i <= 10; i = i + 1) j = j + i;
j;
}));
ASSERT(3, ({
int i = 3;
int j = 0;
for (int i = 0; i <= 10; i = i + 1) j = j + i;
i;
}));
ASSERT(1, 0 || 1);
ASSERT(1, 0 || (2 - 2) || 5);
ASSERT(0, 0 || 0);
ASSERT(0, 0 || (2 - 2));
ASSERT(0, 0 && 1);
ASSERT(0, (2 - 2) && 5);
ASSERT(1, 1 && 5);
ASSERT(3, ({
int i = 0;
goto a;
a:
i++;
b:
i++;
c:
i++;
i;
}));
ASSERT(2, ({
int i = 0;
goto e;
d:
i++;
e:
i++;
f:
i++;
i;
}));
ASSERT(1, ({
int i = 0;
goto i;
g:
i++;
h:
i++;
i:
i++;
i;
}));
ASSERT(1, ({
typedef int foo;
goto foo;
foo:;
1;
}));
ASSERT(3, ({
int i = 0;
for (; i < 10; i++) {
if (i == 3) break;
}
i;
}));
ASSERT(4, ({
int i = 0;
while (1) {
if (i++ == 3) break;
}
i;
}));
ASSERT(3, ({
int i = 0;
for (; i < 10; i++) {
for (;;) break;
if (i == 3) break;
}
i;
}));
ASSERT(4, ({
int i = 0;
while (1) {
while (1) break;
if (i++ == 3) break;
}
i;
}));
ASSERT(10, ({
int i = 0;
int j = 0;
for (; i < 10; i++) {
if (i > 5) continue;
j++;
}
i;
}));
ASSERT(6, ({
int i = 0;
int j = 0;
for (; i < 10; i++) {
if (i > 5) continue;
j++;
}
j;
}));
ASSERT(10, ({
int i = 0;
int j = 0;
for (; !i;) {
for (; j != 10; j++) continue;
break;
}
j;
}));
ASSERT(11, ({
int i = 0;
int j = 0;
while (i++ < 10) {
if (i > 5) continue;
j++;
}
i;
}));
ASSERT(5, ({
int i = 0;
int j = 0;
while (i++ < 10) {
if (i > 5) continue;
j++;
}
j;
}));
ASSERT(11, ({
int i = 0;
int j = 0;
while (!i) {
while (j++ != 10) continue;
break;
}
j;
}));
ASSERT(5, ({
int i = 0;
switch (0) {
case 0:
i = 5;
break;
case 1:
i = 6;
break;
case 2:
i = 7;
break;
}
i;
}));
ASSERT(6, ({
int i = 0;
switch (1) {
case 0:
i = 5;
break;
case 1:
i = 6;
break;
case 2:
i = 7;
break;
}
i;
}));
ASSERT(7, ({
int i = 0;
switch (2) {
case 0:
i = 5;
break;
case 1:
i = 6;
break;
case 2:
i = 7;
break;
}
i;
}));
ASSERT(0, ({
int i = 0;
switch (3) {
case 0:
i = 5;
break;
case 1:
i = 6;
break;
case 2:
i = 7;
break;
}
i;
}));
ASSERT(5, ({
int i = 0;
switch (0) {
case 0:
i = 5;
break;
default:
i = 7;
}
i;
}));
ASSERT(7, ({
int i = 0;
switch (1) {
case 0:
i = 5;
break;
default:
i = 7;
}
i;
}));
ASSERT(2, ({
int i = 0;
switch (1) {
case 0:
0;
case 1:
0;
case 2:
0;
i = 2;
}
i;
}));
ASSERT(0, ({
int i = 0;
switch (3) {
case 0:
0;
case 1:
0;
case 2:
0;
i = 2;
}
i;
}));
ASSERT(3, ({
int i = 0;
switch (-1) {
case 0xffffffff:
i = 3;
break;
}
i;
}));
ASSERT(7, ({
int i = 0;
int j = 0;
do {
j++;
} while (i++ < 6);
j;
}));
ASSERT(4, ({
int i = 0;
int j = 0;
int k = 0;
do {
if (++j > 3) break;
continue;
k++;
} while (1);
j;
}));
ASSERT(0, 0.0 && 0.0);
ASSERT(0, 0.0 && 0.1);
ASSERT(0, 0.3 && 0.0);
ASSERT(1, 0.3 && 0.5);
ASSERT(0, 0.0 || 0.0);
ASSERT(1, 0.0 || 0.1);
ASSERT(1, 0.3 || 0.0);
ASSERT(1, 0.3 || 0.5);
ASSERT(5, ({
int x;
if (0.0)
x = 3;
else
x = 5;
x;
}));
ASSERT(3, ({
int x;
if (0.1)
x = 3;
else
x = 5;
x;
}));
ASSERT(5, ({
int x = 5;
if (0.0) x = 3;
x;
}));
ASSERT(3, ({
int x = 5;
if (0.1) x = 3;
x;
}));
ASSERT(10, ({
double i = 10.0;
int j = 0;
for (; i; i--, j++)
;
j;
}));
ASSERT(10, ({
double i = 10.0;
int j = 0;
do
j++;
while (--i);
j;
}));
ASSERT(2, ({
int i = 0;
switch (7) {
case 0 ... 5:
i = 1;
break;
case 6 ... 20:
i = 2;
break;
}
i;
}));
ASSERT(1, ({
int i = 0;
switch (7) {
case 0 ... 7:
i = 1;
break;
case 8 ... 10:
i = 2;
break;
}
i;
}));
ASSERT(1, ({
int i = 0;
switch (7) {
case 0:
i = 1;
break;
case 7 ... 7:
i = 1;
break;
}
i;
}));
ASSERT(3, ({
void *p = &&v11;
int i = 0;
goto *p;
v11:
i++;
v12:
i++;
v13:
i++;
i;
}));
ASSERT(2, ({
void *p = &&v22;
int i = 0;
goto *p;
v21:
i++;
v22:
i++;
v23:
i++;
i;
}));
ASSERT(1, ({
void *p = &&v33;
int i = 0;
goto *p;
v31:
i++;
v32:
i++;
v33:
i++;
i;
}));
ASSERT(3, ({
static void *p[] = {&&v41, &&v42, &&v43};
int i = 0;
goto *p[0];
v41:
i++;
v42:
i++;
v43:
i++;
i;
}));
ASSERT(2, ({
static void *p[] = {&&v52, &&v52, &&v53};
int i = 0;
goto *p[1];
v51:
i++;
v52:
i++;
v53:
i++;
i;
}));
ASSERT(1, ({
static void *p[] = {&&v62, &&v62, &&v63};
int i = 0;
goto *p[2];
v61:
i++;
v62:
i++;
v63:
i++;
i;
}));
return 0;
}

51
third_party/chibicc/test/decl_test.c vendored Normal file
View file

@ -0,0 +1,51 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(1, ({
char x;
sizeof(x);
}));
ASSERT(2, ({
short int x;
sizeof(x);
}));
ASSERT(2, ({
int short x;
sizeof(x);
}));
ASSERT(4, ({
int x;
sizeof(x);
}));
ASSERT(8, ({
long int x;
sizeof(x);
}));
ASSERT(8, ({
int long x;
sizeof(x);
}));
ASSERT(8, ({
long long x;
sizeof(x);
}));
ASSERT(0, ({
_Bool x = 0;
x;
}));
ASSERT(1, ({
_Bool x = 1;
x;
}));
ASSERT(1, ({
_Bool x = 2;
x;
}));
ASSERT(1, (_Bool)1);
ASSERT(1, (_Bool)2);
ASSERT(0, (_Bool)(char)256);
return 0;
}

50
third_party/chibicc/test/enum_test.c vendored Normal file
View file

@ -0,0 +1,50 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(0, ({
enum { zero, one, two };
zero;
}));
ASSERT(1, ({
enum { zero, one, two };
one;
}));
ASSERT(2, ({
enum { zero, one, two };
two;
}));
ASSERT(5, ({
enum { five = 5, six, seven };
five;
}));
ASSERT(6, ({
enum { five = 5, six, seven };
six;
}));
ASSERT(0, ({
enum { zero, five = 5, three = 3, four };
zero;
}));
ASSERT(5, ({
enum { zero, five = 5, three = 3, four };
five;
}));
ASSERT(3, ({
enum { zero, five = 5, three = 3, four };
three;
}));
ASSERT(4, ({
enum { zero, five = 5, three = 3, four };
four;
}));
ASSERT(4, ({
enum { zero, one, two } x;
sizeof(x);
}));
ASSERT(4, ({
enum t { zero, one, two };
enum t y;
sizeof(y);
}));
return 0;
}

24
third_party/chibicc/test/extern_test.c vendored Normal file
View file

@ -0,0 +1,24 @@
#include "third_party/chibicc/test/test.h"
extern int ext1;
extern int *ext2;
inline int inline_fn(void) {
return 3;
}
int main() {
ASSERT(5, ext1);
ASSERT(5, *ext2);
extern int ext3;
ASSERT(7, ext3);
int ext_fn1(int x);
ASSERT(5, ext_fn1(5));
extern int ext_fn2(int x);
ASSERT(8, ext_fn2(8));
return 0;
}

92
third_party/chibicc/test/float_test.c vendored Normal file
View file

@ -0,0 +1,92 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(35, (float)(char)35);
ASSERT(35, (float)(short)35);
ASSERT(35, (float)(int)35);
ASSERT(35, (float)(long)35);
ASSERT(35, (float)(unsigned char)35);
ASSERT(35, (float)(unsigned short)35);
ASSERT(35, (float)(unsigned int)35);
ASSERT(35, (float)(unsigned long)35);
ASSERT(35, (double)(char)35);
ASSERT(35, (double)(short)35);
ASSERT(35, (double)(int)35);
ASSERT(35, (double)(long)35);
ASSERT(35, (double)(unsigned char)35);
ASSERT(35, (double)(unsigned short)35);
ASSERT(35, (double)(unsigned int)35);
ASSERT(35, (double)(unsigned long)35);
ASSERT(35, (char)(float)35);
ASSERT(35, (short)(float)35);
ASSERT(35, (int)(float)35);
ASSERT(35, (long)(float)35);
ASSERT(35, (unsigned char)(float)35);
ASSERT(35, (unsigned short)(float)35);
ASSERT(35, (unsigned int)(float)35);
ASSERT(35, (unsigned long)(float)35);
ASSERT(35, (char)(double)35);
ASSERT(35, (short)(double)35);
ASSERT(35, (int)(double)35);
ASSERT(35, (long)(double)35);
ASSERT(35, (unsigned char)(double)35);
ASSERT(35, (unsigned short)(double)35);
ASSERT(35, (unsigned int)(double)35);
ASSERT(35, (unsigned long)(double)35);
ASSERT(0x8000000000000000, (double)(unsigned long)(long)-1);
ASSERT(1, 2e3 == 2e3);
ASSERT(0, 2e3 == 2e5);
ASSERT(1, 2.0 == 2);
ASSERT(0, 5.1 < 5);
ASSERT(0, 5.0 < 5);
ASSERT(1, 4.9 < 5);
ASSERT(0, 5.1 <= 5);
ASSERT(1, 5.0 <= 5);
ASSERT(1, 4.9 <= 5);
ASSERT(1, 2e3f == 2e3);
ASSERT(0, 2e3f == 2e5);
ASSERT(1, 2.0f == 2);
ASSERT(0, 5.1f < 5);
ASSERT(0, 5.0f < 5);
ASSERT(1, 4.9f < 5);
ASSERT(0, 5.1f <= 5);
ASSERT(1, 5.0f <= 5);
ASSERT(1, 4.9f <= 5);
ASSERT(6, 2.3 + 3.8);
ASSERT(-1, 2.3 - 3.8);
ASSERT(-3, -3.8);
ASSERT(13, 3.3 * 4);
ASSERT(2, 5.0 / 2);
ASSERT(6, 2.3f + 3.8f);
ASSERT(6, 2.3f + 3.8);
ASSERT(-1, 2.3f - 3.8);
ASSERT(-3, -3.8f);
ASSERT(13, 3.3f * 4);
ASSERT(2, 5.0f / 2);
ASSERT(0, 0.0 / 0.0 == 0.0 / 0.0);
ASSERT(1, 0.0 / 0.0 != 0.0 / 0.0);
ASSERT(0, 0.0 / 0.0 < 0);
ASSERT(0, 0.0 / 0.0 <= 0);
ASSERT(0, 0.0 / 0.0 > 0);
ASSERT(0, 0.0 / 0.0 >= 0);
ASSERT(0, !3.);
ASSERT(1, !0.);
ASSERT(0, !3.f);
ASSERT(1, !0.f);
ASSERT(5, 0.0 ? 3 : 5);
ASSERT(3, 1.2 ? 3 : 5);
return 0;
}

534
third_party/chibicc/test/function_test.c vendored Normal file
View file

@ -0,0 +1,534 @@
#include "third_party/chibicc/test/test.h"
int ret3(void) {
return 3;
return 5;
}
int add2(int x, int y) {
return x + y;
}
int sub2(int x, int y) {
return x - y;
}
int add6(int a, int b, int c, int d, int e, int f) {
return a + b + c + d + e + f;
}
int addx(int *x, int y) {
return *x + y;
}
int sub_char(char a, char b, char c) {
return a - b - c;
}
int fib(int x) {
if (x <= 1) return 1;
return fib(x - 1) + fib(x - 2);
}
int sub_long(long a, long b, long c) {
return a - b - c;
}
int sub_short(short a, short b, short c) {
return a - b - c;
}
int g1;
int *g1_ptr(void) {
return &g1;
}
char int_to_char(int x) {
return x;
}
int div_long(long a, long b) {
return a / b;
}
_Bool bool_fn_add(_Bool x) {
return x + 1;
}
_Bool bool_fn_sub(_Bool x) {
return x - 1;
}
static int static_fn(void) {
return 3;
}
int param_decay(int x[]) {
return x[0];
}
int counter() {
static int i;
static int j = 1 + 1;
return i++ + j++;
}
void ret_none() {
return;
}
_Bool true_fn();
_Bool false_fn();
char char_fn();
short short_fn();
unsigned char uchar_fn();
unsigned short ushort_fn();
char schar_fn();
short sshort_fn();
int add_all(int n, ...);
typedef struct {
int gp_offset;
int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_elem;
typedef __va_elem va_list[1];
int add_all(int n, ...);
int sprintf(char *buf, char *fmt, ...);
int vsprintf(char *buf, char *fmt, va_list ap);
char *fmt(char *buf, char *fmt, ...) {
va_list ap;
*ap = *(__va_elem *)__va_area__;
vsprintf(buf, fmt, ap);
}
double add_double(double x, double y);
float add_float(float x, float y);
float add_float3(float x, float y, float z) {
return x + y + z;
}
double add_double3(double x, double y, double z) {
return x + y + z;
}
int (*fnptr(int (*fn)(int n, ...)))(int, ...) {
return fn;
}
int param_decay2(int x()) {
return x();
}
char *func_fn(void) {
return __func__;
}
char *function_fn(void) {
return __FUNCTION__;
}
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8,
int x9, int x10);
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6,
float x7, float x8, float x9, float x10);
double add10_double(double x1, double x2, double x3, double x4, double x5,
double x6, double x7, double x8, double x9, double x10);
int many_args1(int a, int b, int c, int d, int e, int f, int g, int h) {
return g / h;
}
double many_args2(double a, double b, double c, double d, double e, double f,
double g, double h, double i, double j) {
return i / j;
}
int many_args3(int a, double b, int c, int d, double e, int f, double g, int h,
double i, double j, double k, double l, double m, int n, int o,
double p) {
return o / p;
}
typedef struct {
int a, b;
short c;
char d;
} Ty4;
typedef struct {
int a;
float b;
double c;
} Ty5;
typedef struct {
unsigned char a[3];
} Ty6;
typedef struct {
long a, b, c;
} Ty7;
int struct_test5(Ty5 x, int n);
int struct_test4(Ty4 x, int n);
int struct_test6(Ty6 x, int n);
int struct_test7(Ty7 x, int n);
int struct_test14(Ty4 x, int n) {
switch (n) {
case 0:
return x.a;
case 1:
return x.b;
case 2:
return x.c;
default:
return x.d;
}
}
int struct_test15(Ty5 x, int n) {
switch (n) {
case 0:
return x.a;
case 1:
return x.b;
default:
return x.c;
}
}
typedef struct {
unsigned char a[10];
} Ty20;
typedef struct {
unsigned char a[20];
} Ty21;
Ty4 struct_test24(void);
Ty5 struct_test25(void);
Ty6 struct_test26(void);
Ty20 struct_test27(void);
Ty21 struct_test28(void);
Ty4 struct_test34(void) {
return (Ty4){10, 20, 30, 40};
}
Ty5 struct_test35(void) {
return (Ty5){10, 20, 30};
}
Ty6 struct_test36(void) {
return (Ty6){10, 20, 30};
}
Ty20 struct_test37(void) {
return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
}
Ty21 struct_test38(void) {
return (Ty21){1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
}
inline int inline_fn(void) {
return 3;
}
double to_double(long double x) {
return x;
}
long double to_ldouble(int x) {
return x;
}
int main() {
FILE *f = fopen("/dev/null", "w");
ASSERT(3, ret3());
ASSERT(8, add2(3, 5));
ASSERT(2, sub2(5, 3));
ASSERT(21, add6(1, 2, 3, 4, 5, 6));
ASSERT(66, add6(1, 2, add6(3, 4, 5, 6, 7, 8), 9, 10, 11));
ASSERT(136, add6(1, 2, add6(3, add6(4, 5, 6, 7, 8, 9), 10, 11, 12, 13), 14,
15, 16));
ASSERT(7, add2(3, 4));
ASSERT(1, sub2(4, 3));
ASSERT(55, fib(9));
ASSERT(1, ({ sub_char(7, 3, 3); }));
ASSERT(1, sub_long(7, 3, 3));
ASSERT(1, sub_short(7, 3, 3));
g1 = 3;
ASSERT(3, *g1_ptr());
ASSERT(5, int_to_char(261));
ASSERT(5, int_to_char(261));
ASSERT(-5, div_long(-10, 2));
ASSERT(1, bool_fn_add(3));
ASSERT(0, bool_fn_sub(3));
ASSERT(1, bool_fn_add(-3));
ASSERT(0, bool_fn_sub(-3));
ASSERT(1, bool_fn_add(0));
ASSERT(1, bool_fn_sub(0));
ASSERT(3, static_fn());
ASSERT(3, ({
int x[2];
x[0] = 3;
param_decay(x);
}));
ASSERT(2, counter());
ASSERT(4, counter());
ASSERT(6, counter());
ret_none();
ASSERT(1, true_fn());
ASSERT(0, false_fn());
ASSERT(3, char_fn());
ASSERT(5, short_fn());
ASSERT(6, add_all(3, 1, 2, 3));
ASSERT(5, add_all(4, 1, 2, 3, -1));
{
char buf[100];
fmt(buf, "%d %d %s", 1, 2, "foo");
fprintf(f, "%s\n", buf);
}
ASSERT(0, ({
char buf[100];
sprintf(buf, "%d %d %s", 1, 2, "foo");
strcmp("1 2 foo", buf);
}));
ASSERT(0, ({
char buf[100];
fmt(buf, "%d %d %s", 1, 2, "foo");
strcmp("1 2 foo", buf);
}));
ASSERT(251, uchar_fn());
ASSERT(65528, ushort_fn());
ASSERT(-5, schar_fn());
ASSERT(-8, sshort_fn());
ASSERT(6, add_float(2.3, 3.8));
ASSERT(6, add_double(2.3, 3.8));
ASSERT(7, add_float3(2.5, 2.5, 2.5));
ASSERT(7, add_double3(2.5, 2.5, 2.5));
ASSERT(0, ({
char buf[100];
sprintf(buf, "%.1f", (float)3.5);
strcmp(buf, "3.5");
}));
ASSERT(0, ({
char buf[100];
fmt(buf, "%.1f", (float)3.5);
strcmp(buf, "3.5");
}));
ASSERT(5, (add2)(2, 3));
ASSERT(5, (&add2)(2, 3));
ASSERT(7, ({
int (*fn)(int, int) = add2;
fn(2, 5);
}));
ASSERT(6, fnptr(add_all)(3, 1, 2, 3));
ASSERT(3, param_decay2(ret3));
ASSERT(5, sizeof(__func__));
ASSERT(0, strcmp("main", __func__));
ASSERT(0, strcmp("func_fn", func_fn()));
ASSERT(0, strcmp("main", __FUNCTION__));
ASSERT(0, strcmp("function_fn", function_fn()));
ASSERT(55, add10_int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
ASSERT(55, add10_float(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
ASSERT(55, add10_double(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
ASSERT(0, ({
char buf[200];
sprintf(buf,
"%d %.1f %.1f %.1f %d %d %.1f %d %d %d %d %.1f %d %d %.1f "
"%.1f %.1f %.1f %d",
1, 1.0, 1.0, 1.0, 1, 1, 1.0, 1, 1, 1, 1, 1.0, 1, 1, 1.0, 1.0,
1.0, 1.0, 1);
strcmp("1 1.0 1.0 1.0 1 1 1.0 1 1 1 1 1.0 1 1 1.0 1.0 1.0 1.0 1",
buf);
}));
ASSERT(4, many_args1(1, 2, 3, 4, 5, 6, 40, 10));
ASSERT(4, many_args2(1, 2, 3, 4, 5, 6, 7, 8, 40, 10));
ASSERT(8, many_args3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 80, 10));
ASSERT(10, ({
Ty4 x = {10, 20, 30, 40};
struct_test4(x, 0);
}));
ASSERT(20, ({
Ty4 x = {10, 20, 30, 40};
struct_test4(x, 1);
}));
ASSERT(30, ({
Ty4 x = {10, 20, 30, 40};
struct_test4(x, 2);
}));
ASSERT(40, ({
Ty4 x = {10, 20, 30, 40};
struct_test4(x, 3);
}));
ASSERT(10, ({
Ty5 x = {10, 20, 30};
struct_test5(x, 0);
}));
ASSERT(20, ({
Ty5 x = {10, 20, 30};
struct_test5(x, 1);
}));
ASSERT(30, ({
Ty5 x = {10, 20, 30};
struct_test5(x, 2);
}));
ASSERT(10, ({
Ty6 x = {10, 20, 30};
struct_test6(x, 0);
}));
ASSERT(20, ({
Ty6 x = {10, 20, 30};
struct_test6(x, 1);
}));
ASSERT(30, ({
Ty6 x = {10, 20, 30};
struct_test6(x, 2);
}));
ASSERT(10, ({
Ty7 x = {10, 20, 30};
struct_test7(x, 0);
}));
ASSERT(20, ({
Ty7 x = {10, 20, 30};
struct_test7(x, 1);
}));
ASSERT(30, ({
Ty7 x = {10, 20, 30};
struct_test7(x, 2);
}));
ASSERT(10, ({
Ty4 x = {10, 20, 30, 40};
struct_test14(x, 0);
}));
ASSERT(20, ({
Ty4 x = {10, 20, 30, 40};
struct_test14(x, 1);
}));
ASSERT(30, ({
Ty4 x = {10, 20, 30, 40};
struct_test14(x, 2);
}));
ASSERT(40, ({
Ty4 x = {10, 20, 30, 40};
struct_test14(x, 3);
}));
ASSERT(10, ({
Ty5 x = {10, 20, 30};
struct_test15(x, 0);
}));
ASSERT(20, ({
Ty5 x = {10, 20, 30};
struct_test15(x, 1);
}));
ASSERT(30, ({
Ty5 x = {10, 20, 30};
struct_test15(x, 2);
}));
ASSERT(10, struct_test24().a);
ASSERT(20, struct_test24().b);
ASSERT(30, struct_test24().c);
ASSERT(40, struct_test24().d);
ASSERT(10, struct_test25().a);
ASSERT(20, struct_test25().b);
ASSERT(30, struct_test25().c);
ASSERT(10, struct_test26().a[0]);
ASSERT(20, struct_test26().a[1]);
ASSERT(30, struct_test26().a[2]);
ASSERT(10, struct_test27().a[0]);
ASSERT(60, struct_test27().a[5]);
ASSERT(100, struct_test27().a[9]);
ASSERT(1, struct_test28().a[0]);
ASSERT(5, struct_test28().a[4]);
ASSERT(10, struct_test28().a[9]);
ASSERT(15, struct_test28().a[14]);
ASSERT(20, struct_test28().a[19]);
ASSERT(10, struct_test34().a);
ASSERT(20, struct_test34().b);
ASSERT(30, struct_test34().c);
ASSERT(40, struct_test34().d);
ASSERT(10, struct_test35().a);
ASSERT(20, struct_test35().b);
ASSERT(30, struct_test35().c);
ASSERT(10, struct_test36().a[0]);
ASSERT(20, struct_test36().a[1]);
ASSERT(30, struct_test36().a[2]);
ASSERT(10, struct_test37().a[0]);
ASSERT(60, struct_test37().a[5]);
ASSERT(100, struct_test37().a[9]);
ASSERT(1, struct_test38().a[0]);
ASSERT(5, struct_test38().a[4]);
ASSERT(10, struct_test38().a[9]);
ASSERT(15, struct_test38().a[14]);
ASSERT(20, struct_test38().a[19]);
ASSERT(5, (***add2)(2, 3));
ASSERT(3, inline_fn());
ASSERT(0, ({
char buf[100];
sprintf(buf, "%Lf", (long double)12.3);
strncmp(buf, "12.3", 4);
}));
ASSERT(1, to_double(3.5) == 3.5);
ASSERT(0, to_double(3.5) == 3);
ASSERT(1, (long double)5.0 == (long double)5.0);
ASSERT(0, (long double)5.0 == (long double)5.2);
ASSERT(1, to_ldouble(5.0) == 5.0);
ASSERT(0, to_ldouble(5.0) == 5.2);
}

10
third_party/chibicc/test/generic_test.c vendored Normal file
View file

@ -0,0 +1,10 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(1, _Generic(100.0, double : 1, int * : 2, int : 3, float : 4));
ASSERT(2, _Generic((int *)0, double : 1, int * : 2, int : 3, float : 4));
ASSERT(2, _Generic((int[3]){}, double : 1, int * : 2, int : 3, float : 4));
ASSERT(3, _Generic(100, double : 1, int * : 2, int : 3, float : 4));
ASSERT(4, _Generic(100f, double : 1, int * : 2, int : 3, float : 4));
return 0;
}

5
third_party/chibicc/test/include1.h vendored Normal file
View file

@ -0,0 +1,5 @@
#include "third_party/chibicc/test/include2.h"
char *include1_filename = __FILE__;
int include1_line = __LINE__;
int include1 = 5;

1
third_party/chibicc/test/include2.h vendored Normal file
View file

@ -0,0 +1 @@
int include2 = 7;

1
third_party/chibicc/test/include3.h vendored Normal file
View file

@ -0,0 +1 @@
#define foo 3

1
third_party/chibicc/test/include4.h vendored Normal file
View file

@ -0,0 +1 @@
#define foo 4

View file

@ -0,0 +1,793 @@
#include "third_party/chibicc/test/test.h"
char g3 = 3;
short g4 = 4;
int g5 = 5;
long g6 = 6;
int g9[3] = {0, 1, 2};
struct {
char a;
int b;
} g11[2] = {{1, 2}, {3, 4}};
struct {
int a[2];
} g12[2] = {{{1, 2}}};
union {
int a;
char b[8];
} g13[2] = {0x01020304, 0x05060708};
char g17[] = "foobar";
char g18[10] = "foobar";
char g19[3] = "foobar";
char *g20 = g17 + 0;
char *g21 = g17 + 3;
char *g22 = &g17 - 3;
char *g23[] = {g17 + 0, g17 + 3, g17 - 3};
int g24 = 3;
int *g25 = &g24;
int g26[3] = {1, 2, 3};
int *g27 = g26 + 1;
int *g28 = &g11[1].a;
long g29 = (long)(long)g26;
struct {
struct {
int a[3];
} a;
} g30 = {{{1, 2, 3}}};
int *g31 = g30.a.a;
struct {
int a[2];
} g40[2] = {{1, 2}, 3, 4};
struct {
int a[2];
} g41[2] = {1, 2, 3, 4};
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
char *g44 = {"foo"};
union {
int a;
char b[4];
} g50 = {.b[2] = 0x12};
union {
int a;
} g51[2] = {};
typedef char T60[];
T60 g60 = {1, 2, 3};
T60 g61 = {1, 2, 3, 4, 5, 6};
typedef struct {
char a, b[];
} T65;
T65 g65 = {'f', 'o', 'o', 0};
T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0};
int main() {
ASSERT(1, ({
int x[3] = {1, 2, 3};
x[0];
}));
ASSERT(2, ({
int x[3] = {1, 2, 3};
x[1];
}));
ASSERT(3, ({
int x[3] = {1, 2, 3};
x[2];
}));
ASSERT(3, ({
int x[3] = {1, 2, 3};
x[2];
}));
ASSERT(2, ({
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
x[0][1];
}));
ASSERT(4, ({
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
x[1][0];
}));
ASSERT(6, ({
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
x[1][2];
}));
ASSERT(0, ({
int x[3] = {};
x[0];
}));
ASSERT(0, ({
int x[3] = {};
x[1];
}));
ASSERT(0, ({
int x[3] = {};
x[2];
}));
ASSERT(2, ({
int x[2][3] = {{1, 2}};
x[0][1];
}));
ASSERT(0, ({
int x[2][3] = {{1, 2}};
x[1][0];
}));
ASSERT(0, ({
int x[2][3] = {{1, 2}};
x[1][2];
}));
ASSERT('a', ({
char x[4] = "abc";
x[0];
}));
ASSERT('c', ({
char x[4] = "abc";
x[2];
}));
ASSERT(0, ({
char x[4] = "abc";
x[3];
}));
ASSERT('a', ({
char x[2][4] = {"abc", "def"};
x[0][0];
}));
ASSERT(0, ({
char x[2][4] = {"abc", "def"};
x[0][3];
}));
ASSERT('d', ({
char x[2][4] = {"abc", "def"};
x[1][0];
}));
ASSERT('f', ({
char x[2][4] = {"abc", "def"};
x[1][2];
}));
ASSERT(4, ({
int x[] = {1, 2, 3, 4};
x[3];
}));
ASSERT(16, ({
int x[] = {1, 2, 3, 4};
sizeof(x);
}));
ASSERT(4, ({
char x[] = "foo";
sizeof(x);
}));
ASSERT(4, ({
typedef char T[];
T x = "foo";
T y = "x";
sizeof(x);
}));
ASSERT(2, ({
typedef char T[];
T x = "foo";
T y = "x";
sizeof(y);
}));
ASSERT(2, ({
typedef char T[];
T x = "x";
T y = "foo";
sizeof(x);
}));
ASSERT(4, ({
typedef char T[];
T x = "x";
T y = "foo";
sizeof(y);
}));
ASSERT(1, ({
struct {
int a;
int b;
int c;
} x = {1, 2, 3};
x.a;
}));
ASSERT(2, ({
struct {
int a;
int b;
int c;
} x = {1, 2, 3};
x.b;
}));
ASSERT(3, ({
struct {
int a;
int b;
int c;
} x = {1, 2, 3};
x.c;
}));
ASSERT(1, ({
struct {
int a;
int b;
int c;
} x = {1};
x.a;
}));
ASSERT(0, ({
struct {
int a;
int b;
int c;
} x = {1};
x.b;
}));
ASSERT(0, ({
struct {
int a;
int b;
int c;
} x = {1};
x.c;
}));
ASSERT(1, ({
struct {
int a;
int b;
} x[2] = {{1, 2}, {3, 4}};
x[0].a;
}));
ASSERT(2, ({
struct {
int a;
int b;
} x[2] = {{1, 2}, {3, 4}};
x[0].b;
}));
ASSERT(3, ({
struct {
int a;
int b;
} x[2] = {{1, 2}, {3, 4}};
x[1].a;
}));
ASSERT(4, ({
struct {
int a;
int b;
} x[2] = {{1, 2}, {3, 4}};
x[1].b;
}));
ASSERT(0, ({
struct {
int a;
int b;
} x[2] = {{1, 2}};
x[1].b;
}));
ASSERT(0, ({
struct {
int a;
int b;
} x = {};
x.a;
}));
ASSERT(0, ({
struct {
int a;
int b;
} x = {};
x.b;
}));
ASSERT(5, ({
typedef struct {
int a, b, c, d, e, f;
} T;
T x = {1, 2, 3, 4, 5, 6};
T y;
y = x;
y.e;
}));
ASSERT(2, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y, z;
z = y = x;
z.b;
}));
ASSERT(1, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y = x;
y.a;
}));
ASSERT(4, ({
union {
int a;
char b[4];
} x = {0x01020304};
x.b[0];
}));
ASSERT(3, ({
union {
int a;
char b[4];
} x = {0x01020304};
x.b[1];
}));
ASSERT(0x01020304, ({
union {
struct {
char a, b, c, d;
} e;
int f;
} x = {{4, 3, 2, 1}};
x.f;
}));
ASSERT(3, g3);
ASSERT(4, g4);
ASSERT(5, g5);
ASSERT(6, g6);
ASSERT(0, g9[0]);
ASSERT(1, g9[1]);
ASSERT(2, g9[2]);
ASSERT(1, g11[0].a);
ASSERT(2, g11[0].b);
ASSERT(3, g11[1].a);
ASSERT(4, g11[1].b);
ASSERT(1, g12[0].a[0]);
ASSERT(2, g12[0].a[1]);
ASSERT(0, g12[1].a[0]);
ASSERT(0, g12[1].a[1]);
ASSERT(4, g13[0].b[0]);
ASSERT(3, g13[0].b[1]);
ASSERT(8, g13[1].b[0]);
ASSERT(7, g13[1].b[1]);
ASSERT(7, sizeof(g17));
ASSERT(10, sizeof(g18));
ASSERT(3, sizeof(g19));
ASSERT(0, memcmp(g17, "foobar", 7));
ASSERT(0, memcmp(g18, "foobar\0\0\0", 10));
ASSERT(0, memcmp(g19, "foo", 3));
ASSERT(0, strcmp(g20, "foobar"));
ASSERT(0, strcmp(g21, "bar"));
ASSERT(0, strcmp(g22 + 3, "foobar"));
ASSERT(0, strcmp(g23[0], "foobar"));
ASSERT(0, strcmp(g23[1], "bar"));
ASSERT(0, strcmp(g23[2] + 3, "foobar"));
ASSERT(3, g24);
ASSERT(3, *g25);
ASSERT(2, *g27);
ASSERT(3, *g28);
ASSERT(1, *(int *)g29);
ASSERT(1, g31[0]);
ASSERT(2, g31[1]);
ASSERT(3, g31[2]);
ASSERT(1, g40[0].a[0]);
ASSERT(2, g40[0].a[1]);
ASSERT(3, g40[1].a[0]);
ASSERT(4, g40[1].a[1]);
ASSERT(1, g41[0].a[0]);
ASSERT(2, g41[0].a[1]);
ASSERT(3, g41[1].a[0]);
ASSERT(4, g41[1].a[1]);
ASSERT(0, ({
int x[2][3] = {0, 1, 2, 3, 4, 5};
x[0][0];
}));
ASSERT(3, ({
int x[2][3] = {0, 1, 2, 3, 4, 5};
x[1][0];
}));
ASSERT(0, ({
struct {
int a;
int b;
} x[2] = {0, 1, 2, 3};
x[0].a;
}));
ASSERT(2, ({
struct {
int a;
int b;
} x[2] = {0, 1, 2, 3};
x[1].a;
}));
ASSERT(0, strcmp(g43[0], "foo"));
ASSERT(0, strcmp(g43[1], "bar"));
ASSERT(0, strcmp(g44, "foo"));
ASSERT(3, ({
int a[] = {
1,
2,
3,
};
a[2];
}));
ASSERT(1, ({
struct {
int a, b, c;
} x = {
1,
2,
3,
};
x.a;
}));
ASSERT(2, ({
enum {
x,
y,
z,
};
z;
}));
ASSERT(3, sizeof(g60));
ASSERT(6, sizeof(g61));
ASSERT(4, sizeof(g65));
ASSERT(7, sizeof(g66));
ASSERT(0, strcmp(g65.b, "oo"));
ASSERT(0, strcmp(g66.b, "oobar"));
ASSERT(4, ({
int x[3] = {1, 2, 3, [0] = 4, 5};
x[0];
}));
ASSERT(5, ({
int x[3] = {1, 2, 3, [0] = 4, 5};
x[1];
}));
ASSERT(3, ({
int x[3] = {1, 2, 3, [0] = 4, 5};
x[2];
}));
ASSERT(10, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[0][0];
}));
ASSERT(11, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[0][1];
}));
ASSERT(8, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[0][2];
}));
ASSERT(12, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[1][0];
}));
ASSERT(5, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[1][1];
}));
ASSERT(6, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
x[1][2];
}));
ASSERT(7, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[0][0];
}));
ASSERT(8, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[0][1];
}));
ASSERT(3, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[0][2];
}));
ASSERT(9, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[1][0];
}));
ASSERT(10, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[1][1];
}));
ASSERT(6, ({
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
x[1][2];
}));
ASSERT(7, ((int[10]){[3] = 7})[3]);
ASSERT(0, ((int[10]){[3] = 7})[4]);
ASSERT(10, ({
char x[] = {[10 - 3] = 1, 2, 3};
sizeof(x);
}));
ASSERT(20, ({
char x[][2] = {[8][1] = 1, 2};
sizeof(x);
}));
ASSERT(3, sizeof(g60));
ASSERT(6, sizeof(g61));
ASSERT(4, sizeof(g65));
ASSERT(7, sizeof(g66));
ASSERT(0, strcmp(g65.b, "oo"));
ASSERT(0, strcmp(g66.b, "oobar"));
ASSERT(7, ((int[10]){[3] 7})[3]);
ASSERT(0, ((int[10]){[3] 7})[4]);
ASSERT(4, ({
struct {
int a, b;
} x = {1, 2, .b = 3, .a = 4};
x.a;
}));
ASSERT(3, ({
struct {
int a, b;
} x = {1, 2, .b = 3, .a = 4};
x.b;
}));
ASSERT(1, ({
struct {
struct {
int a, b;
} c;
} x = {.c = 1, 2};
x.c.a;
}));
ASSERT(2, ({
struct {
struct {
int a, b;
} c;
} x = {.c = 1, 2};
x.c.b;
}));
ASSERT(0, ({
struct {
struct {
int a, b;
} c;
} x = {.c.b = 1};
x.c.a;
}));
ASSERT(1, ({
struct {
struct {
int a, b;
} c;
} x = {.c.b = 1};
x.c.b;
}));
ASSERT(1, ({
struct {
int a[2];
} x = {.a = 1, 2};
x.a[0];
}));
ASSERT(2, ({
struct {
int a[2];
} x = {.a = 1, 2};
x.a[1];
}));
ASSERT(0, ({
struct {
int a[2];
} x = {.a[1] = 1};
x.a[0];
}));
ASSERT(1, ({
struct {
int a[2];
} x = {.a[1] = 1};
x.a[1];
}));
ASSERT(3, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[0].a;
}));
ASSERT(4, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[0].b;
}));
ASSERT(0, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[1].a;
}));
ASSERT(1, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[1].b;
}));
ASSERT(2, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[2].a;
}));
ASSERT(0, ({
struct {
int a, b;
} x[] = {
[1].b = 1,
2,
[0] = 3,
4,
};
x[2].b;
}));
ASSERT(1, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y[] = {x};
y[0].a;
}));
ASSERT(2, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y[] = {x};
y[0].b;
}));
ASSERT(0, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y[] = {x, [0].b = 3};
y[0].a;
}));
ASSERT(3, ({
typedef struct {
int a, b;
} T;
T x = {1, 2};
T y[] = {x, [0].b = 3};
y[0].b;
}));
ASSERT(5, ((struct { int a, b, c; }){.c = 5}).c);
ASSERT(0, ((struct { int a, b, c; }){.c = 5}).a);
ASSERT(0x00ff, ({
union {
unsigned short a;
char b[2];
} x = {.b[0] = 0xff};
x.a;
}));
ASSERT(0xff00, ({
union {
unsigned short a;
char b[2];
} x = {.b[1] = 0xff};
x.a;
}));
ASSERT(0x00120000, g50.a);
ASSERT(0, g51[0].a);
ASSERT(0, g51[1].a);
ASSERT(1, ({
struct {
struct {
int a;
struct {
int b;
};
};
int c;
} x = {1, 2, 3, .b = 4, 5};
x.a;
}));
ASSERT(4, ({
struct {
struct {
int a;
struct {
int b;
};
};
int c;
} x = {1, 2, 3, .b = 4, 5};
x.b;
}));
ASSERT(5, ({
struct {
struct {
int a;
struct {
int b;
};
};
int c;
} x = {1, 2, 3, .b = 4, 5};
x.c;
}));
ASSERT(16, ({
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
sizeof(x);
}));
ASSERT(0, ({
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16);
}));
return 0;
}

8183
third_party/chibicc/test/int128_test.c vendored Normal file

File diff suppressed because it is too large Load diff

20
third_party/chibicc/test/line_test.c vendored Normal file
View file

@ -0,0 +1,20 @@
#include "third_party/chibicc/test/test.h"
int main() {
#line 500 "foo"
ASSERT(501, __LINE__);
ASSERT(0, strcmp(__FILE__, "foo"));
#line 800 "bar"
ASSERT(801, __LINE__);
ASSERT(0, strcmp(__FILE__, "bar"));
#line 1
ASSERT(2, __LINE__);
# 200 "xyz" 2 3
ASSERT(201, __LINE__);
ASSERT(0, strcmp(__FILE__, "xyz"));
return 0;
}

108
third_party/chibicc/test/literal_test.c vendored Normal file
View file

@ -0,0 +1,108 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(97, 'a');
ASSERT(10, '\n');
ASSERT(-128, '\x80');
ASSERT(511, 0777);
ASSERT(0, 0x0);
ASSERT(10, 0xa);
ASSERT(10, 0XA);
ASSERT(48879, 0xbeef);
ASSERT(48879, 0xBEEF);
ASSERT(48879, 0XBEEF);
ASSERT(0, 0b0);
ASSERT(1, 0b1);
ASSERT(47, 0b101111);
ASSERT(47, 0B101111);
ASSERT(4, sizeof(0));
ASSERT(8, sizeof(0L));
ASSERT(8, sizeof(0LU));
ASSERT(8, sizeof(0UL));
ASSERT(8, sizeof(0LL));
ASSERT(8, sizeof(0LLU));
ASSERT(8, sizeof(0Ull));
ASSERT(8, sizeof(0l));
ASSERT(8, sizeof(0ll));
ASSERT(8, sizeof(0x0L));
ASSERT(8, sizeof(0b0L));
ASSERT(4, sizeof(2147483647));
ASSERT(8, sizeof(2147483648));
ASSERT(-1, 0xffffffffffffffff);
ASSERT(8, sizeof(0xffffffffffffffff));
ASSERT(4, sizeof(4294967295U));
ASSERT(8, sizeof(4294967296U));
ASSERT(3, -1U >> 30);
ASSERT(3, -1Ul >> 62);
ASSERT(3, -1ull >> 62);
ASSERT(1, 0xffffffffffffffffl >> 63);
ASSERT(1, 0xffffffffffffffffll >> 63);
ASSERT(-1, 18446744073709551615);
ASSERT(8, sizeof(18446744073709551615));
ASSERT(-1, 18446744073709551615 >> 63);
ASSERT(-1, 0xffffffffffffffff);
ASSERT(8, sizeof(0xffffffffffffffff));
ASSERT(1, 0xffffffffffffffff >> 63);
ASSERT(-1, 01777777777777777777777);
ASSERT(8, sizeof(01777777777777777777777));
ASSERT(1, 01777777777777777777777 >> 63);
ASSERT(-1,
0b1111111111111111111111111111111111111111111111111111111111111111);
ASSERT(
8,
sizeof(
0b1111111111111111111111111111111111111111111111111111111111111111));
ASSERT(
1,
0b1111111111111111111111111111111111111111111111111111111111111111 >> 63);
ASSERT(8, sizeof(2147483648));
ASSERT(4, sizeof(2147483647));
ASSERT(8, sizeof(0x1ffffffff));
ASSERT(4, sizeof(0xffffffff));
ASSERT(1, 0xffffffff >> 31);
ASSERT(8, sizeof(040000000000));
ASSERT(4, sizeof(037777777777));
ASSERT(1, 037777777777 >> 31);
ASSERT(8, sizeof(0b111111111111111111111111111111111));
ASSERT(4, sizeof(0b11111111111111111111111111111111));
ASSERT(1, 0b11111111111111111111111111111111 >> 31);
ASSERT(-1, 1 << 31 >> 31);
ASSERT(-1, 01 << 31 >> 31);
ASSERT(-1, 0x1 << 31 >> 31);
ASSERT(-1, 0b1 << 31 >> 31);
0.0;
1.0;
3e+8;
0x10.1p0;
.1E4f;
ASSERT(4, sizeof(8f));
ASSERT(4, sizeof(0.3F));
ASSERT(8, sizeof(0.));
ASSERT(8, sizeof(.0));
ASSERT(16, sizeof(5.l));
ASSERT(16, sizeof(2.0L));
Assert(1, size\
of(char),
"sizeof(char)");
ASSERT(4, sizeof(L'\0'));
ASSERT(97, L'a');
return 0;
}

413
third_party/chibicc/test/macro_test.c vendored Normal file
View file

@ -0,0 +1,413 @@
#include "third_party/chibicc/test/include1.h"
#include "third_party/chibicc/test/test.h"
/* clang-format off */
char *main_filename1 = __FILE__;
int main_line1 = __LINE__;
#define LINE() __LINE__
int main_line2 = LINE();
#
/* */ #
int ret3(void) { return 3; }
int dbl(int x) { return x*x; }
int add2(int x, int y) {
return x + y;
}
int add6(int a, int b, int c, int d, int e, int f) {
return a + b + c + d + e + f;
}
int main() {
ASSERT(5, include1);
ASSERT(7, include2);
#if 0
#include "/no/such/file"
ASSERT(0, 1);
#if nested
#endif
#endif
int m = 0;
#if 1
m = 5;
#endif
ASSERT(5, m);
#if 1
# if 0
# if 1
foo bar
# endif
# endif
m = 3;
#endif
ASSERT(3, m);
#if 1-1
# if 1
# endif
# if 1
# else
# endif
# if 0
# else
# endif
m = 2;
#else
# if 1
m = 3;
# endif
#endif
ASSERT(3, m);
#if 1
m = 2;
#else
m = 3;
#endif
ASSERT(2, m);
#if 1
m = 2;
#else
m = 3;
#endif
ASSERT(2, m);
#if 0
m = 1;
#elif 0
m = 2;
#elif 3+5
m = 3;
#elif 1*5
m = 4;
#endif
ASSERT(3, m);
#if 1+5
m = 1;
#elif 1
m = 2;
#elif 3
m = 2;
#endif
ASSERT(1, m);
#if 0
m = 1;
#elif 1
# if 1
m = 2;
# else
m = 3;
# endif
#else
m = 5;
#endif
ASSERT(2, m);
int M1 = 5;
#define M1 3
ASSERT(3, M1);
#define M1 4
ASSERT(4, M1);
#define M1 3+4+
ASSERT(12, M1 5);
#define M1 3+4
ASSERT(23, M1*5);
#define ASSERT_ Assert(
#define if 5
#define five "5"
#define END )
ASSERT_ 5, if, five END;
#undef ASSERT_
#undef if
#undef five
#undef END
if (0);
#define M 5
#if M
m = 5;
#else
m = 6;
#endif
ASSERT(5, m);
#define M 5
#if M-5
m = 6;
#elif M
m = 5;
#endif
ASSERT(5, m);
int M2 = 6;
#define M2 M2 + 3
ASSERT(9, M2);
#define M3 M2 + 3
ASSERT(12, M3);
int M4 = 3;
#define M4 M5 * 5
#define M5 M4 + 2
ASSERT(13, M4);
#ifdef M6
m = 5;
#else
m = 3;
#endif
ASSERT(3, m);
#define M6
#ifdef M6
m = 5;
#else
m = 3;
#endif
ASSERT(5, m);
#ifndef M7
m = 3;
#else
m = 5;
#endif
ASSERT(3, m);
#define M7
#ifndef M7
m = 3;
#else
m = 5;
#endif
ASSERT(5, m);
#if 0
#ifdef NO_SUCH_MACRO
#endif
#ifndef NO_SUCH_MACRO
#endif
#else
#endif
#define M7() 1
int M7 = 5;
ASSERT(1, M7());
ASSERT(5, M7);
#define M7 ()
ASSERT(3, ret3 M7);
#define M8(x,y) x+y
ASSERT(7, M8(3, 4));
#define M8(x,y) x*y
ASSERT(24, M8(3+4, 4+5));
#define M8(x,y) (x)*(y)
ASSERT(63, M8(3+4, 4+5));
#define M8(x,y) x y
ASSERT(9, M8(, 4+5));
#define M8(x,y) x*y
ASSERT(20, M8((2+3), 4));
#define M8(x,y) x*y
ASSERT(12, M8((2,3), 4));
#define dbl(x) M10(x) * x
#define M10(x) dbl(x) + 3
ASSERT(10, dbl(2));
#define M11(x) #x
ASSERT('a', M11( a!b `""c)[0]);
ASSERT('!', M11( a!b `""c)[1]);
ASSERT('b', M11( a!b `""c)[2]);
ASSERT(' ', M11( a!b `""c)[3]);
ASSERT('`', M11( a!b `""c)[4]);
ASSERT('"', M11( a!b `""c)[5]);
ASSERT('"', M11( a!b `""c)[6]);
ASSERT('c', M11( a!b `""c)[7]);
ASSERT(0, M11( a!b `""c)[8]);
#define paste(x,y) x##y
ASSERT(15, paste(1,5));
ASSERT(255, paste(0,xff));
ASSERT(3, ({ int foobar=3; paste(foo,bar); }));
ASSERT(5, paste(5,));
ASSERT(5, paste(,5));
#define i 5
ASSERT(101, ({ int i3=100; paste(1+i,3); }));
#undef i
#define paste2(x) x##5
ASSERT(26, paste2(1+2));
#define paste3(x) 2##x
ASSERT(23, paste3(1+2));
#define paste4(x, y, z) x##y##z
ASSERT(123, paste4(1,2,3));
#define M12
#if defined(M12)
m = 3;
#else
m = 4;
#endif
ASSERT(3, m);
#define M12
#if defined M12
m = 3;
#else
m = 4;
#endif
ASSERT(3, m);
#if defined(M12) - 1
m = 3;
#else
m = 4;
#endif
ASSERT(4, m);
#if defined(NO_SUCH_MACRO)
m = 3;
#else
m = 4;
#endif
ASSERT(4, m);
#if no_such_symbol == 0
m = 5;
#else
m = 6;
#endif
ASSERT(5, m);
#define STR(x) #x
#define M12(x) STR(x)
#define M13(x) M12(foo.x)
ASSERT(0, strcmp(M13(bar), "foo.bar"));
#define M13(x) M12(foo. x)
ASSERT(0, strcmp(M13(bar), "foo. bar"));
#define M12 foo
#define M13(x) STR(x)
#define M14(x) M13(x.M12)
ASSERT(0, strcmp(M14(bar), "bar.foo"));
#define M14(x) M13(x. M12)
ASSERT(0, strcmp(M14(bar), "bar. foo"));
#include "third_party/chibicc/test/include3.h"
ASSERT(3, foo);
#include "third_party/chibicc/test/include4.h"
ASSERT(4, foo);
#define M13 "third_party/chibicc/test/include3.h"
#include M13
ASSERT(3, foo);
#define M13 < third_party/chibicc/test/include4.h
#include M13 >
ASSERT(4, foo);
#undef foo
ASSERT(1, __STDC__);
ASSERT(0, strcmp(main_filename1, "third_party/chibicc/test/macro_test.c"));
ASSERT(5, main_line1);
ASSERT(7, main_line2);
ASSERT(0, strcmp(include1_filename, "third_party/chibicc/test/include1.h"));
ASSERT(4, include1_line);
#define M14(...) 3
ASSERT(3, M14());
#define M14(...) __VA_ARGS__
ASSERT(2, M14() 2);
ASSERT(5, M14(5));
#define M14(...) add2(__VA_ARGS__)
ASSERT(8, M14(2, 6));
#define M14(...) add6(1,2,__VA_ARGS__,6)
ASSERT(21, M14(3,4,5));
#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)
ASSERT(21, M14(3,4,5));
#define M14(args...) 3
ASSERT(3, M14());
#define M14(x, ...) x
ASSERT(5, M14(5));
#define M14(args...) args
ASSERT(2, M14() 2);
ASSERT(5, M14(5));
#define M14(args...) add2(args)
ASSERT(8, M14(2, 6));
#define M14(args...) add6(1,2,args,6)
ASSERT(21, M14(3,4,5));
#define M14(x, args...) add6(1,2,x,args,6)
ASSERT(21, M14(3,4,5));
#define M14(x, args...) x
ASSERT(5, M14(5));
#define CONCAT(x,y) x##y
ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); }));
ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));
ASSERT(11, strlen(__DATE__));
ASSERT(8, strlen(__TIME__));
ASSERT(0, __COUNTER__);
ASSERT(1, __COUNTER__);
ASSERT(2, __COUNTER__);
ASSERT(24, strlen(__TIMESTAMP__));
ASSERT(0, strcmp(__BASE_FILE__, "third_party/chibicc/test/macro_test.c"));
#define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(,) __VA_ARGS__)
ASSERT(0, ({ char buf[100]; M30(buf, "foo"); strcmp(buf, "foo"); }));
ASSERT(0, ({ char buf[100]; M30(buf, "foo%d", 3); strcmp(buf, "foo3"); }));
ASSERT(0, ({ char buf[100]; M30(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); }));
#define M31(buf, fmt, ...) sprintf(buf, fmt, ## __VA_ARGS__)
ASSERT(0, ({ char buf[100]; M31(buf, "foo"); strcmp(buf, "foo"); }));
ASSERT(0, ({ char buf[100]; M31(buf, "foo%d", 3); strcmp(buf, "foo3"); }));
ASSERT(0, ({ char buf[100]; M31(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); }));
#define M31(x, y) (1, ##x y)
ASSERT(3, M31(, 3));
return 0;
}

View file

@ -0,0 +1,17 @@
#include "third_party/chibicc/test/test.h"
typedef struct {
int a;
char b;
int c;
double d;
} T;
int main() {
ASSERT(0, offsetof(T, a));
ASSERT(4, offsetof(T, b));
ASSERT(8, offsetof(T, c));
ASSERT(16, offsetof(T, d));
return 0;
}

202
third_party/chibicc/test/pointer_test.c vendored Normal file
View file

@ -0,0 +1,202 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(3, ({
int x = 3;
*&x;
}));
ASSERT(3, ({
int x = 3;
int *y = &x;
int **z = &y;
**z;
}));
ASSERT(5, ({
int x = 3;
int y = 5;
*(&x + 1);
}));
ASSERT(3, ({
int x = 3;
int y = 5;
*(&y - 1);
}));
ASSERT(5, ({
int x = 3;
int y = 5;
*(&x - (-1));
}));
ASSERT(5, ({
int x = 3;
int *y = &x;
*y = 5;
x;
}));
ASSERT(7, ({
int x = 3;
int y = 5;
*(&x + 1) = 7;
y;
}));
ASSERT(7, ({
int x = 3;
int y = 5;
*(&y - 2 + 1) = 7;
x;
}));
ASSERT(5, ({
int x = 3;
(&x + 2) - &x + 3;
}));
ASSERT(8, ({
int x, y;
x = 3;
y = 5;
x + y;
}));
ASSERT(8, ({
int x = 3, y = 5;
x + y;
}));
ASSERT(3, ({
int x[2];
int *y = &x;
*y = 3;
*x;
}));
ASSERT(3, ({
int x[3];
*x = 3;
*(x + 1) = 4;
*(x + 2) = 5;
*x;
}));
ASSERT(4, ({
int x[3];
*x = 3;
*(x + 1) = 4;
*(x + 2) = 5;
*(x + 1);
}));
ASSERT(5, ({
int x[3];
*x = 3;
*(x + 1) = 4;
*(x + 2) = 5;
*(x + 2);
}));
ASSERT(0, ({
int x[2][3];
int *y = x;
*y = 0;
**x;
}));
ASSERT(1, ({
int x[2][3];
int *y = x;
*(y + 1) = 1;
*(*x + 1);
}));
ASSERT(2, ({
int x[2][3];
int *y = x;
*(y + 2) = 2;
*(*x + 2);
}));
ASSERT(3, ({
int x[2][3];
int *y = x;
*(y + 3) = 3;
**(x + 1);
}));
ASSERT(4, ({
int x[2][3];
int *y = x;
*(y + 4) = 4;
*(*(x + 1) + 1);
}));
ASSERT(5, ({
int x[2][3];
int *y = x;
*(y + 5) = 5;
*(*(x + 1) + 2);
}));
ASSERT(3, ({
int x[3];
*x = 3;
x[1] = 4;
x[2] = 5;
*x;
}));
ASSERT(4, ({
int x[3];
*x = 3;
x[1] = 4;
x[2] = 5;
*(x + 1);
}));
ASSERT(5, ({
int x[3];
*x = 3;
x[1] = 4;
x[2] = 5;
*(x + 2);
}));
ASSERT(5, ({
int x[3];
*x = 3;
x[1] = 4;
x[2] = 5;
*(x + 2);
}));
ASSERT(5, ({
int x[3];
*x = 3;
x[1] = 4;
2 [x] = 5;
*(x + 2);
}));
ASSERT(0, ({
int x[2][3];
int *y = x;
y[0] = 0;
x[0][0];
}));
ASSERT(1, ({
int x[2][3];
int *y = x;
y[1] = 1;
x[0][1];
}));
ASSERT(2, ({
int x[2][3];
int *y = x;
y[2] = 2;
x[0][2];
}));
ASSERT(3, ({
int x[2][3];
int *y = x;
y[3] = 3;
x[1][0];
}));
ASSERT(4, ({
int x[2][3];
int *y = x;
y[4] = 4;
x[1][1];
}));
ASSERT(5, ({
int x[2][3];
int *y = x;
y[5] = 5;
x[1][2];
}));
return 0;
}

View file

@ -0,0 +1,9 @@
#include "third_party/chibicc/test/test.h"
#pragma once
#include "third_party/chibicc/test/pragma-once_test.c"
int main() {
return 0;
}

113
third_party/chibicc/test/sizeof_test.c vendored Normal file
View file

@ -0,0 +1,113 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(1, sizeof(char));
ASSERT(2, sizeof(short));
ASSERT(2, sizeof(short int));
ASSERT(2, sizeof(int short));
ASSERT(4, sizeof(int));
ASSERT(8, sizeof(long));
ASSERT(8, sizeof(long int));
ASSERT(8, sizeof(long int));
ASSERT(8, sizeof(char *));
ASSERT(8, sizeof(int *));
ASSERT(8, sizeof(long *));
ASSERT(8, sizeof(int **));
ASSERT(8, sizeof(int(*)[4]));
ASSERT(32, sizeof(int *[4]));
ASSERT(16, sizeof(int[4]));
ASSERT(48, sizeof(int[3][4]));
ASSERT(8, sizeof(struct {
int a;
int b;
}));
ASSERT(8, sizeof(-10 + (long)5));
ASSERT(8, sizeof(-10 - (long)5));
ASSERT(8, sizeof(-10 * (long)5));
ASSERT(8, sizeof(-10 / (long)5));
ASSERT(8, sizeof((long)-10 + 5));
ASSERT(8, sizeof((long)-10 - 5));
ASSERT(8, sizeof((long)-10 * 5));
ASSERT(8, sizeof((long)-10 / 5));
ASSERT(1, ({
char i;
sizeof(++i);
}));
ASSERT(1, ({
char i;
sizeof(i++);
}));
ASSERT(8, sizeof(int(*)[10]));
ASSERT(8, sizeof(int(*)[][10]));
ASSERT(4, sizeof(struct { int x, y[]; }));
ASSERT(1, sizeof(char));
ASSERT(1, sizeof(signed char));
ASSERT(1, sizeof(signed char signed));
ASSERT(1, sizeof(unsigned char));
ASSERT(1, sizeof(unsigned char unsigned));
ASSERT(2, sizeof(short));
ASSERT(2, sizeof(int short));
ASSERT(2, sizeof(short int));
ASSERT(2, sizeof(signed short));
ASSERT(2, sizeof(int short signed));
ASSERT(2, sizeof(unsigned short));
ASSERT(2, sizeof(int short unsigned));
ASSERT(4, sizeof(int));
ASSERT(4, sizeof(signed int));
ASSERT(4, sizeof(signed));
ASSERT(4, sizeof(signed signed));
ASSERT(4, sizeof(unsigned int));
ASSERT(4, sizeof(unsigned));
ASSERT(4, sizeof(unsigned unsigned));
ASSERT(8, sizeof(long));
ASSERT(8, sizeof(signed long));
ASSERT(8, sizeof(signed long int));
ASSERT(8, sizeof(unsigned long));
ASSERT(8, sizeof(unsigned long int));
ASSERT(8, sizeof(long long));
ASSERT(8, sizeof(signed long long));
ASSERT(8, sizeof(signed long long int));
ASSERT(8, sizeof(unsigned long long));
ASSERT(8, sizeof(unsigned long long int));
ASSERT(1, sizeof((char)1));
ASSERT(2, sizeof((short)1));
ASSERT(4, sizeof((int)1));
ASSERT(8, sizeof((long)1));
ASSERT(4, sizeof((char)1 + (char)1));
ASSERT(4, sizeof((short)1 + (short)1));
ASSERT(4, sizeof(1 ? 2 : 3));
ASSERT(4, sizeof(1 ? (short)2 : (char)3));
ASSERT(8, sizeof(1 ? (long)2 : (char)3));
ASSERT(1, sizeof(char) << 31 >> 31);
ASSERT(1, sizeof(char) << 63 >> 63);
ASSERT(4, sizeof(float));
ASSERT(8, sizeof(double));
ASSERT(4, sizeof(1f + 2));
ASSERT(8, sizeof(1.0 + 2));
ASSERT(4, sizeof(1f - 2));
ASSERT(8, sizeof(1.0 - 2));
ASSERT(4, sizeof(1f * 2));
ASSERT(8, sizeof(1.0 * 2));
ASSERT(4, sizeof(1f / 2));
ASSERT(8, sizeof(1.0 / 2));
ASSERT(16, sizeof(long double));
ASSERT(1, sizeof(main));
return 0;
}

105
third_party/chibicc/test/string_test.c vendored Normal file
View file

@ -0,0 +1,105 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(0, ""[0]);
ASSERT(1, sizeof(""));
ASSERT(97, "abc"[0]);
ASSERT(98, "abc"[1]);
ASSERT(99, "abc"[2]);
ASSERT(0, "abc"[3]);
ASSERT(4, sizeof("abc"));
ASSERT(7, "\a"[0]);
ASSERT(8, "\b"[0]);
ASSERT(9, "\t"[0]);
ASSERT(10, "\n"[0]);
ASSERT(11, "\v"[0]);
ASSERT(12, "\f"[0]);
ASSERT(13, "\r"[0]);
ASSERT(27, "\e"[0]);
ASSERT(106, "\j"[0]);
ASSERT(107, "\k"[0]);
ASSERT(108, "\l"[0]);
ASSERT(7, "\ax\ny"[0]);
ASSERT(120, "\ax\ny"[1]);
ASSERT(10, "\ax\ny"[2]);
ASSERT(121, "\ax\ny"[3]);
ASSERT(0, "\0"[0]);
ASSERT(16, "\20"[0]);
ASSERT(65, "\101"[0]);
ASSERT(104, "\1500"[0]);
ASSERT(0, "\x00"[0]);
ASSERT(119, "\x77"[0]);
ASSERT(7, sizeof("abc"
"def"));
ASSERT(9, sizeof("abc"
"d"
"efgh"));
ASSERT(0, strcmp("abc"
"d"
"\nefgh",
"abcd\nefgh"));
ASSERT(0, !strcmp("abc"
"d",
"abcd\nefgh"));
ASSERT(0, strcmp("\x9"
"0",
"\t0"));
ASSERT(16, sizeof(L"abc"
""));
ASSERT(28, sizeof(L"abc"
"def"));
ASSERT(28, sizeof(L"abc"
L"def"));
ASSERT(14, sizeof(u"abc"
"def"));
ASSERT(14, sizeof(u"abc"
u"def"));
ASSERT(L'a', (L"abc"
"def")[0]);
ASSERT(L'd', (L"abc"
"def")[3]);
ASSERT(L'\0', (L"abc"
"def")[6]);
ASSERT(u'a', (u"abc"
"def")[0]);
ASSERT(u'd', (u"abc"
"def")[3]);
ASSERT(u'\0', (u"abc"
"def")[6]);
ASSERT(L'', (""
L"")[0]);
ASSERT(0343, ("\343\201\202"
L"")[0]);
ASSERT(0201, ("\343\201\202"
L"")[1]);
ASSERT(0202, ("\343\201\202"
L"")[2]);
ASSERT(0, ("\343\201\202"
L"")[3]);
ASSERT(L'a', ("a"
"b"
L"c")[0]);
ASSERT(L'b', ("a"
"b"
L"c")[1]);
ASSERT(L'c', ("a"
"b"
L"c")[2]);
ASSERT(0, ("a"
"b"
L"c")[3]);
return 0;
}

379
third_party/chibicc/test/struct_test.c vendored Normal file
View file

@ -0,0 +1,379 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(1, ({
struct {
int a;
int b;
} x;
x.a = 1;
x.b = 2;
x.a;
}));
ASSERT(2, ({
struct {
int a;
int b;
} x;
x.a = 1;
x.b = 2;
x.b;
}));
ASSERT(1, ({
struct {
char a;
int b;
char c;
} x;
x.a = 1;
x.b = 2;
x.c = 3;
x.a;
}));
ASSERT(2, ({
struct {
char a;
int b;
char c;
} x;
x.b = 1;
x.b = 2;
x.c = 3;
x.b;
}));
ASSERT(3, ({
struct {
char a;
int b;
char c;
} x;
x.a = 1;
x.b = 2;
x.c = 3;
x.c;
}));
ASSERT(0, ({
struct {
char a;
char b;
} x[3];
char *p = x;
p[0] = 0;
x[0].a;
}));
ASSERT(1, ({
struct {
char a;
char b;
} x[3];
char *p = x;
p[1] = 1;
x[0].b;
}));
ASSERT(2, ({
struct {
char a;
char b;
} x[3];
char *p = x;
p[2] = 2;
x[1].a;
}));
ASSERT(3, ({
struct {
char a;
char b;
} x[3];
char *p = x;
p[3] = 3;
x[1].b;
}));
ASSERT(6, ({
struct {
char a[3];
char b[5];
} x;
char *p = &x;
x.a[0] = 6;
p[0];
}));
ASSERT(7, ({
struct {
char a[3];
char b[5];
} x;
char *p = &x;
x.b[0] = 7;
p[3];
}));
ASSERT(6, ({
struct {
struct {
char b;
} a;
} x;
x.a.b = 6;
x.a.b;
}));
ASSERT(4, ({
struct {
int a;
} x;
sizeof(x);
}));
ASSERT(8, ({
struct {
int a;
int b;
} x;
sizeof(x);
}));
ASSERT(8, ({
struct {
int a, b;
} x;
sizeof(x);
}));
ASSERT(12, ({
struct {
int a[3];
} x;
sizeof(x);
}));
ASSERT(16, ({
struct {
int a;
} x[4];
sizeof(x);
}));
ASSERT(24, ({
struct {
int a[3];
} x[2];
sizeof(x);
}));
ASSERT(2, ({
struct {
char a;
char b;
} x;
sizeof(x);
}));
ASSERT(0, ({
struct {
} x;
sizeof(x);
}));
ASSERT(8, ({
struct {
char a;
int b;
} x;
sizeof(x);
}));
ASSERT(8, ({
struct {
int a;
char b;
} x;
sizeof(x);
}));
ASSERT(8, ({
struct t {
int a;
int b;
} x;
struct t y;
sizeof(y);
}));
ASSERT(8, ({
struct t {
int a;
int b;
};
struct t y;
sizeof(y);
}));
ASSERT(2, ({
struct t {
char a[2];
};
{
struct t {
char a[4];
};
}
struct t y;
sizeof(y);
}));
ASSERT(3, ({
struct t {
int x;
};
int t = 1;
struct t y;
y.x = 2;
t + y.x;
}));
ASSERT(3, ({
struct t {
char a;
} x;
struct t *y = &x;
x.a = 3;
y->a;
}));
ASSERT(3, ({
struct t {
char a;
} x;
struct t *y = &x;
y->a = 3;
x.a;
}));
ASSERT(3, ({
struct {
int a, b;
} x, y;
x.a = 3;
y = x;
y.a;
}));
ASSERT(7, ({
struct t {
int a, b;
};
struct t x;
x.a = 7;
struct t y;
struct t *z = &y;
*z = x;
y.a;
}));
ASSERT(7, ({
struct t {
int a, b;
};
struct t x;
x.a = 7;
struct t y, *p = &x, *q = &y;
*q = *p;
y.a;
}));
ASSERT(5, ({
struct t {
char a, b;
} x, y;
x.a = 5;
y = x;
y.a;
}));
ASSERT(3, ({
struct {
int a, b;
} x, y;
x.a = 3;
y = x;
y.a;
}));
ASSERT(7, ({
struct t {
int a, b;
};
struct t x;
x.a = 7;
struct t y;
struct t *z = &y;
*z = x;
y.a;
}));
ASSERT(7, ({
struct t {
int a, b;
};
struct t x;
x.a = 7;
struct t y, *p = &x, *q = &y;
*q = *p;
y.a;
}));
ASSERT(5, ({
struct t {
char a, b;
} x, y;
x.a = 5;
y = x;
y.a;
}));
ASSERT(8, ({
struct t {
int a;
int b;
} x;
struct t y;
sizeof(y);
}));
ASSERT(8, ({
struct t {
int a;
int b;
};
struct t y;
sizeof(y);
}));
ASSERT(16, ({
struct {
char a;
long b;
} x;
sizeof(x);
}));
ASSERT(4, ({
struct {
char a;
short b;
} x;
sizeof(x);
}));
ASSERT(8, ({
struct foo *bar;
sizeof(bar);
}));
ASSERT(4, ({
struct T *foo;
struct T {
int x;
};
sizeof(struct T);
}));
ASSERT(1, ({
struct T {
struct T *next;
int x;
} a;
struct T b;
b.x = 1;
a.next = &b;
a.next->x;
}));
ASSERT(4, ({
typedef struct T T;
struct T {
int x;
};
sizeof(T);
}));
return 0;
}

11
third_party/chibicc/test/test.h vendored Normal file
View file

@ -0,0 +1,11 @@
#include "libc/fmt/fmt.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#define ASSERT(x, y) Assert2(x, y, #y, __FILE__, __LINE__)
#define ASSERT128(x, y) Assert128(x, y, #y, __FILE__, __LINE__)
void Assert(long, long, char *);
void Assert2(long, long, char *, char *, int);
void Assert128(__int128, __int128, char *, char *, int);

100
third_party/chibicc/test/test.mk vendored Normal file
View file

@ -0,0 +1,100 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# C Compiler Unit Tests
#
# OVERVIEW
#
# This makefile compiles and runs each test twice. The first with
# GCC-built chibicc, and a second time with chibicc-built chibicc
PKGS += THIRD_PARTY_CHIBICC_TEST
THIRD_PARTY_CHIBICC_TEST_A = o/$(MODE)/third_party/chibicc/test/test.a
THIRD_PARTY_CHIBICC_TEST2_A = o/$(MODE)/third_party/chibicc/test/test2.a
THIRD_PARTY_CHIBICC_TEST_FILES := $(wildcard third_party/chibicc/test/*)
THIRD_PARTY_CHIBICC_TEST_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_TEST_FILES))
THIRD_PARTY_CHIBICC_TEST_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_CHIBICC_TEST_SRCS))
THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES))
THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok)
THIRD_PARTY_CHIBICC_TEST_COMS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%.com) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%2.com)
THIRD_PARTY_CHIBICC_TEST_OBJS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o)
THIRD_PARTY_CHIBICC_TEST2_OBJS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.o)
THIRD_PARTY_CHIBICC_TEST_BINS = \
$(THIRD_PARTY_CHIBICC_TEST_COMS) \
$(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.dbg)
THIRD_PARTY_CHIBICC_TEST_CHECKS = \
$(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.runs) \
$(THIRD_PARTY_CHIBICC_TEST_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \
LIBC_RUNTIME \
LIBC_FMT \
LIBC_STR \
LIBC_STDIO \
LIBC_STUBS \
LIBC_NEXGEN32E \
LIBC_UNICODE \
LIBC_MEM \
THIRD_PARTY_COMPILER_RT
THIRD_PARTY_CHIBICC_TEST_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_CHIBICC_TEST_A): \
third_party/chibicc/test/ \
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
$(THIRD_PARTY_CHIBICC_TEST_OBJS)
$(THIRD_PARTY_CHIBICC_TEST2_A): \
third_party/chibicc/test/ \
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
$(THIRD_PARTY_CHIBICC_TEST2_OBJS)
$(THIRD_PARTY_CHIBICC_TEST_A).pkg: \
$(THIRD_PARTY_CHIBICC_TEST_OBJS) \
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \
$(THIRD_PARTY_CHIBICC_TEST2_OBJS) \
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/third_party/chibicc/test/%.com.dbg: \
$(THIRD_PARTY_CHIBICC_TEST_DEPS) \
$(THIRD_PARTY_CHIBICC_TEST_A) \
o/$(MODE)/third_party/chibicc/test/%.chibicc.o \
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
$(THIRD_PARTY_CHIBICC_TEST_DEPS) \
$(THIRD_PARTY_CHIBICC_TEST2_A) \
o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)
.PHONY: o/$(MODE)/third_party/chibicc/test
o/$(MODE)/third_party/chibicc/test: \
$(THIRD_PARTY_CHIBICC_TEST_BINS) \
$(THIRD_PARTY_CHIBICC_TEST_CHECKS) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.s) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.s)

View file

@ -0,0 +1,18 @@
#include "third_party/chibicc/test/test.h"
_Thread_local int x;
void add(void) {
x += 3;
}
_Noreturn int test(void) {
x = 7;
add();
ASSERT(10, x);
exit(0);
}
int main(void) {
test();
}

49
third_party/chibicc/test/typedef_test.c vendored Normal file
View file

@ -0,0 +1,49 @@
#include "third_party/chibicc/test/test.h"
typedef int MyInt, MyInt2[4];
typedef int;
int main() {
ASSERT(1, ({
typedef int t;
t x = 1;
x;
}));
ASSERT(1, ({
typedef struct {
int a;
} t;
t x;
x.a = 1;
x.a;
}));
ASSERT(1, ({
typedef int t;
t t = 1;
t;
}));
ASSERT(2, ({
typedef struct {
int a;
} t;
{ typedef int t; }
t x;
x.a = 2;
x.a;
}));
ASSERT(4, ({
typedef t;
t x;
sizeof(x);
}));
ASSERT(3, ({
MyInt x = 3;
x;
}));
ASSERT(16, ({
MyInt2 x;
sizeof(x);
}));
return 0;
}

29
third_party/chibicc/test/typeof_test.c vendored Normal file
View file

@ -0,0 +1,29 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(3, ({
typeof(int) x = 3;
x;
}));
ASSERT(3, ({
typeof(1) x = 3;
x;
}));
ASSERT(4, ({
int x;
typeof(x) y;
sizeof(y);
}));
ASSERT(8, ({
int x;
typeof(&x) y;
sizeof(y);
}));
ASSERT(4, ({
typeof("foo") x;
sizeof(x);
}));
ASSERT(12, sizeof(typeof(struct { int a, b, c; })));
return 0;
}

138
third_party/chibicc/test/unicode_test.c vendored Normal file
View file

@ -0,0 +1,138 @@
#include "third_party/chibicc/test/test.h"
/* TODO(jart): shl overflow in read_escaped_char */
#define STR(x) #x
typedef unsigned short char16_t;
typedef unsigned int char32_t;
typedef int wchar_t;
int π = 3;
int main() {
ASSERT(4, sizeof(L'\0'));
ASSERT(97, L'a');
ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3"));
ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E"));
ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E"));
ASSERT(0, strcmp("🌮", "\U0001F32E"));
ASSERT(-1, L'\xffffffff' >> 31);
ASSERT(946, L'β');
ASSERT(12354, L'');
ASSERT(127843, L'🍣');
ASSERT(2, sizeof(u'\0'));
ASSERT(1, u'\xffff' >> 15);
ASSERT(97, u'a');
ASSERT(946, u'β');
ASSERT(12354, u'');
ASSERT(62307, u'🍣');
ASSERT(0, strcmp(STR(u'a'), "u'a'"));
ASSERT(4, sizeof(U'\0'));
ASSERT(1, U'\xffffffff' >> 31);
ASSERT(97, U'a');
ASSERT(946, U'β');
ASSERT(12354, U'');
ASSERT(127843, U'🍣');
ASSERT(0, strcmp(STR(U'a'), "U'a'"));
ASSERT(4, sizeof(u8"abc"));
ASSERT(0, strcmp(u8"abc", "abc"));
ASSERT(0, strcmp(STR(u8"a"), "u8\"a\""));
ASSERT(2, sizeof(u""));
ASSERT(10, sizeof(u"\xffzzz"));
ASSERT(0, memcmp(u"", "\0\0", 2));
ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8));
ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8));
ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6));
ASSERT(u'β', u"βb"[0]);
ASSERT(u'b', u"βb"[1]);
ASSERT(0, u"βb"[2]);
ASSERT(0, strcmp(STR(u"a"), "u\"a\""));
ASSERT(4, sizeof(U""));
ASSERT(20, sizeof(U"\xffzzz"));
ASSERT(0, memcmp(U"", "\0\0\0\0", 4));
ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8));
ASSERT(u'β', U"βb"[0]);
ASSERT(u'b', U"βb"[1]);
ASSERT(0, U"βb"[2]);
ASSERT(1, U"\xffffffff"[0] >> 31);
ASSERT(0, strcmp(STR(U"a"), "U\"a\""));
ASSERT(4, sizeof(L""));
ASSERT(20, sizeof(L"\xffzzz"));
ASSERT(0, memcmp(L"", "\0\0\0\0", 4));
ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8));
ASSERT(u'β', L"βb"[0]);
ASSERT(u'b', L"βb"[1]);
ASSERT(0, L"βb"[2]);
ASSERT(-1, L"\xffffffff"[0] >> 31);
ASSERT(0, strcmp(STR(L"a"), "L\"a\""));
ASSERT(u'α', ({
char16_t x[] = u"αβ";
x[0];
}));
ASSERT(u'β', ({
char16_t x[] = u"αβ";
x[1];
}));
ASSERT(6, ({
char16_t x[] = u"αβ";
sizeof(x);
}));
ASSERT(U'🤔', ({
char32_t x[] = U"🤔x";
x[0];
}));
ASSERT(U'x', ({
char32_t x[] = U"🤔x";
x[1];
}));
ASSERT(12, ({
char32_t x[] = U"🤔x";
sizeof(x);
}));
ASSERT(L'🤔', ({
wchar_t x[] = L"🤔x";
x[0];
}));
ASSERT(L'x', ({
wchar_t x[] = L"🤔x";
x[1];
}));
ASSERT(12, ({
wchar_t x[] = L"🤔x";
sizeof(x);
}));
ASSERT(3, π);
ASSERT(3, ({
int β0¾ = 3;
β0¾;
}));
ASSERT(5, ({
int $$$ = 5;
$$$;
}));
return 0;
}

132
third_party/chibicc/test/union_test.c vendored Normal file
View file

@ -0,0 +1,132 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(8, ({
union {
int a;
char b[6];
} x;
sizeof(x);
}));
ASSERT(3, ({
union {
int a;
char b[4];
} x;
x.a = 515;
x.b[0];
}));
ASSERT(2, ({
union {
int a;
char b[4];
} x;
x.a = 515;
x.b[1];
}));
ASSERT(0, ({
union {
int a;
char b[4];
} x;
x.a = 515;
x.b[2];
}));
ASSERT(0, ({
union {
int a;
char b[4];
} x;
x.a = 515;
x.b[3];
}));
ASSERT(3, ({
union {
int a, b;
} x, y;
x.a = 3;
y.a = 5;
y = x;
y.a;
}));
ASSERT(3, ({
union {
struct {
int a, b;
} c;
} x, y;
x.c.b = 3;
y.c.b = 5;
y = x;
y.c.b;
}));
ASSERT(0xef, ({
union {
struct {
unsigned char a, b, c, d;
};
long e;
} x;
x.e = 0xdeadbeef;
x.a;
}));
ASSERT(0xbe, ({
union {
struct {
unsigned char a, b, c, d;
};
long e;
} x;
x.e = 0xdeadbeef;
x.b;
}));
ASSERT(0xad, ({
union {
struct {
unsigned char a, b, c, d;
};
long e;
} x;
x.e = 0xdeadbeef;
x.c;
}));
ASSERT(0xde, ({
union {
struct {
unsigned char a, b, c, d;
};
long e;
} x;
x.e = 0xdeadbeef;
x.d;
}));
ASSERT(3, ({
struct {
union {
int a, b;
};
union {
int c, d;
};
} x;
x.a = 3;
x.b;
}));
ASSERT(5, ({
struct {
union {
int a, b;
};
union {
int c, d;
};
} x;
x.d = 5;
x.c;
}));
return 0;
}

View file

@ -0,0 +1,58 @@
#include "third_party/chibicc/test/test.h"
static int ret10(void) {
return 10;
}
int main() {
ASSERT((long)-5, -10 + (long)5);
ASSERT((long)-15, -10 - (long)5);
ASSERT((long)-50, -10 * (long)5);
ASSERT((long)-2, -10 / (long)5);
ASSERT(1, -2 < (long)-1);
ASSERT(1, -2 <= (long)-1);
ASSERT(0, -2 > (long)-1);
ASSERT(0, -2 >= (long)-1);
ASSERT(1, (long)-2 < -1);
ASSERT(1, (long)-2 <= -1);
ASSERT(0, (long)-2 > -1);
ASSERT(0, (long)-2 >= -1);
ASSERT(0, 2147483647 + 2147483647 + 2);
ASSERT((long)-1, ({
long x;
x = -1;
x;
}));
ASSERT(1, ({
char x[3];
x[0] = 0;
x[1] = 1;
x[2] = 2;
char *y = x + 1;
y[0];
}));
ASSERT(0, ({
char x[3];
x[0] = 0;
x[1] = 1;
x[2] = 2;
char *y = x + 1;
y[-1];
}));
ASSERT(5, ({
struct t {
char a;
} x, y;
x.a = 5;
y = x;
y.a;
}));
ASSERT(10, (1 ? ret10 : (void *)0)());
return 0;
}

52
third_party/chibicc/test/varargs_test.c vendored Normal file
View file

@ -0,0 +1,52 @@
#include "third_party/chibicc/test/test.h"
int sum1(int x, ...) {
va_list ap;
va_start(ap, x);
for (;;) {
int y = va_arg(ap, int);
if (y == 0) return x;
x += y;
}
}
int sum2(int x, ...) {
va_list ap;
va_start(ap, x);
for (;;) {
double y = va_arg(ap, double);
x += y;
int z = va_arg(ap, int);
if (z == 0) return x;
x += z;
}
}
void fmt(char *buf, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
va_list ap2;
va_copy(ap2, ap);
vsprintf(buf, fmt, ap2);
va_end(buf);
}
int main() {
ASSERT(6, sum1(1, 2, 3, 0));
ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0));
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0,
15, 16.0, 17, 18.0, 19, 20.0, 0));
ASSERT(0, ({
char buf[100];
fmt(buf, "%d %d", 2, 3);
strcmp(buf, "2 3");
}));
return 0;
}

244
third_party/chibicc/test/variable_test.c vendored Normal file
View file

@ -0,0 +1,244 @@
#include "third_party/chibicc/test/test.h"
int g1, g2[4];
static int g3 = 3;
int main() {
ASSERT(3, ({
int a;
a = 3;
a;
}));
ASSERT(3, ({
int a = 3;
a;
}));
ASSERT(8, ({
int a = 3;
int z = 5;
a + z;
}));
ASSERT(3, ({
int a = 3;
a;
}));
ASSERT(8, ({
int a = 3;
int z = 5;
a + z;
}));
ASSERT(6, ({
int a;
int b;
a = b = 3;
a + b;
}));
ASSERT(3, ({
int foo = 3;
foo;
}));
ASSERT(8, ({
int foo123 = 3;
int bar = 5;
foo123 + bar;
}));
ASSERT(4, ({
int x;
sizeof(x);
}));
ASSERT(4, ({
int x;
sizeof x;
}));
ASSERT(8, ({
int *x;
sizeof(x);
}));
ASSERT(16, ({
int x[4];
sizeof(x);
}));
ASSERT(48, ({
int x[3][4];
sizeof(x);
}));
ASSERT(16, ({
int x[3][4];
sizeof(*x);
}));
ASSERT(4, ({
int x[3][4];
sizeof(**x);
}));
ASSERT(5, ({
int x[3][4];
sizeof(**x) + 1;
}));
ASSERT(5, ({
int x[3][4];
sizeof **x + 1;
}));
ASSERT(4, ({
int x[3][4];
sizeof(**x + 1);
}));
ASSERT(4, ({
int x = 1;
sizeof(x = 2);
}));
ASSERT(1, ({
int x = 1;
sizeof(x = 2);
x;
}));
ASSERT(0, g1);
ASSERT(3, ({
g1 = 3;
g1;
}));
ASSERT(0, ({
g2[0] = 0;
g2[1] = 1;
g2[2] = 2;
g2[3] = 3;
g2[0];
}));
ASSERT(1, ({
g2[0] = 0;
g2[1] = 1;
g2[2] = 2;
g2[3] = 3;
g2[1];
}));
ASSERT(2, ({
g2[0] = 0;
g2[1] = 1;
g2[2] = 2;
g2[3] = 3;
g2[2];
}));
ASSERT(3, ({
g2[0] = 0;
g2[1] = 1;
g2[2] = 2;
g2[3] = 3;
g2[3];
}));
ASSERT(4, sizeof(g1));
ASSERT(16, sizeof(g2));
ASSERT(1, ({
char x = 1;
x;
}));
ASSERT(1, ({
char x = 1;
char y = 2;
x;
}));
ASSERT(2, ({
char x = 1;
char y = 2;
y;
}));
ASSERT(1, ({
char x;
sizeof(x);
}));
ASSERT(10, ({
char x[10];
sizeof(x);
}));
ASSERT(2, ({
int x = 2;
{ int x = 3; }
x;
}));
ASSERT(2, ({
int x = 2;
{ int x = 3; }
int y = 4;
x;
}));
ASSERT(3, ({
int x = 2;
{ x = 3; }
x;
}));
ASSERT(7, ({
int x;
int y;
char z;
char *a = &y;
char *b = &z;
b - a;
}));
ASSERT(1, ({
int x;
char y;
int z;
char *a = &y;
char *b = &z;
b - a;
}));
ASSERT(8, ({
long x;
sizeof(x);
}));
ASSERT(2, ({
short x;
sizeof(x);
}));
ASSERT(24, ({
char *x[3];
sizeof(x);
}));
ASSERT(8, ({
char(*x)[3];
sizeof(x);
}));
ASSERT(1, ({
char(x);
sizeof(x);
}));
ASSERT(3, ({
char(x)[3];
sizeof(x);
}));
ASSERT(12, ({
char(x[3])[4];
sizeof(x);
}));
ASSERT(4, ({
char(x[3])[4];
sizeof(x[0]);
}));
ASSERT(3, ({
char *x[3];
char y;
x[0] = &y;
y = 3;
x[0][0];
}));
ASSERT(4, ({
char x[3];
char(*y)[3] = x;
y[0][0] = 4;
y[0][0];
}));
{ void *x; }
ASSERT(3, g3);
return 0;
}

56
third_party/chibicc/test/vector_test.c vendored Normal file
View file

@ -0,0 +1,56 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "third_party/chibicc/test/test.h"
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)));
typedef double double2 __attribute__((__vector_size__(16)));
typedef double double2a1 __attribute__((__vector_size__(16), __aligned__(1)));
typedef double double2a16 __attribute__((__vector_size__(16), __aligned__(16)));
int main(void) {
ASSERT(16, sizeof(float4));
ASSERT(16, sizeof(float4a1));
ASSERT(16, sizeof(float4a16));
ASSERT(16, sizeof(double2));
ASSERT(16, sizeof(double2a1));
ASSERT(16, sizeof(double2a16));
ASSERT(16, _Alignof(float4));
ASSERT(1, _Alignof(float4a1));
ASSERT(16, _Alignof(float4a16));
ASSERT(16, _Alignof(double2));
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]); */
return 0;
}

86
third_party/chibicc/test/vla_test.c vendored Normal file
View file

@ -0,0 +1,86 @@
#include "third_party/chibicc/test/test.h"
int main() {
ASSERT(20, ({
int n = 5;
int x[n];
sizeof(x);
}));
ASSERT((5 + 1) * (8 * 2) * 4, ({
int m = 5, n = 8;
int x[m + 1][n * 2];
sizeof(x);
}));
ASSERT(8, ({
char n = 10;
int(*x)[n][n + 2];
sizeof(x);
}));
ASSERT(480, ({
char n = 10;
int(*x)[n][n + 2];
sizeof(*x);
}));
ASSERT(48, ({
char n = 10;
int(*x)[n][n + 2];
sizeof(**x);
}));
ASSERT(4, ({
char n = 10;
int(*x)[n][n + 2];
sizeof(***x);
}));
ASSERT(60, ({
char n = 3;
int x[5][n];
sizeof(x);
}));
ASSERT(12, ({
char n = 3;
int x[5][n];
sizeof(*x);
}));
ASSERT(60, ({
char n = 3;
int x[n][5];
sizeof(x);
}));
ASSERT(20, ({
char n = 3;
int x[n][5];
sizeof(*x);
}));
ASSERT(0, ({
int n = 10;
int x[n + 1][n + 6];
int *p = x;
for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i;
x[0][0];
}));
ASSERT(5, ({
int n = 10;
int x[n + 1][n + 6];
int *p = x;
for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i;
x[0][5];
}));
ASSERT(5 * 16 + 2, ({
int n = 10;
int x[n + 1][n + 6];
int *p = x;
for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i;
x[5][2];
}));
ASSERT(10, ({
int n = 5;
sizeof(char[2][n]);
}));
return 0;
}

View file

@ -1,5 +1,7 @@
#include "third_party/chibicc/chibicc.h"
#define LOOKINGAT(TOK, OP) lookingat(TOK, OP, strlen(OP))
// Input file
static File *current_file;
@ -30,17 +32,13 @@ static void verror_at(char *filename, char *input, int line_no, char *loc,
// Find a line containing `loc`.
char *line = loc;
while (input < line && line[-1] != '\n') line--;
char *end = loc;
while (*end && *end != '\n') end++;
// Print out the line.
int indent = fprintf(stderr, "%s:%d: ", filename, line_no);
fprintf(stderr, "%.*s\n", (int)(end - line), line);
// Show the error message.
int pos = str_width(line, loc - line) + indent;
fprintf(stderr, "%*s", pos, ""); // print pos spaces.
fprintf(stderr, "^ ");
vfprintf(stderr, fmt, ap);
@ -49,9 +47,9 @@ static void verror_at(char *filename, char *input, int line_no, char *loc,
void error_at(char *loc, char *fmt, ...) {
int line_no = 1;
for (char *p = current_file->contents; p < loc; p++)
for (char *p = current_file->contents; p < loc; p++) {
if (*p == '\n') line_no++;
}
va_list ap;
va_start(ap, fmt);
verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap);
@ -59,10 +57,14 @@ void error_at(char *loc, char *fmt, ...) {
}
void error_tok(Token *tok, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt,
ap);
va_list ap, va;
va_start(va, fmt);
for (Token *t = tok; t; t = t->origin) {
va_copy(ap, va);
verror_at(t->file->name, t->file->contents, t->line_no, t->loc, fmt, ap);
va_end(ap);
}
va_end(va);
exit(1);
}
@ -73,19 +75,29 @@ void warn_tok(Token *tok, char *fmt, ...) {
ap);
}
forceinline int compare_strings(const char *a, const char *b, size_t n) {
size_t i = 0;
if (!n-- || a == b) return 0;
while (a[i] == b[i] && b[i] && i < n) ++i;
return (a[i] & 0xff) - (b[i] & 0xff);
}
static int is_space(int c) {
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
c == '\v';
}
static bool lookingat(const char *a, const char *b, size_t n) {
return !compare_strings(a, b, n);
}
// Consumes the current token if it matches `op`.
bool equal(Token *tok, char *op) {
return strlen(op) == tok->len && !strncmp(tok->loc, op, tok->len);
bool equal(Token *tok, char *op, size_t n) {
return n == tok->len && !compare_strings(tok->loc, op, tok->len);
}
// Ensure that the current token is `op`.
Token *skip(Token *tok, char *op) {
if (!equal(tok, op)) error_tok(tok, "expected '%s'", op);
return tok->next;
}
bool consume(Token **rest, Token *tok, char *str) {
if (equal(tok, str)) {
bool consume(Token **rest, Token *tok, char *str, size_t n) {
if (n == tok->len && !compare_strings(tok->loc, str, n)) {
*rest = tok->next;
return true;
}
@ -93,6 +105,12 @@ bool consume(Token **rest, Token *tok, char *str) {
return false;
}
// Ensure that the current token is `op`.
Token *skip(Token *tok, char *op) {
if (!EQUAL(tok, op)) error_tok(tok, "expected '%s'", op);
return tok->next;
}
// Create a new token and add it as the next token of `cur`.
static Token *new_token(TokenKind kind, char *start, char *end) {
Token *tok = calloc(1, sizeof(Token));
@ -103,15 +121,10 @@ static Token *new_token(TokenKind kind, char *start, char *end) {
tok->filename = current_file->display_name;
tok->at_bol = at_bol;
tok->has_space = has_space;
at_bol = has_space = false;
return tok;
}
static bool starts_with(char *p, char *q) {
return strncmp(p, q, strlen(q)) == 0;
}
// Read an identifier and returns a pointer pointing to the end
// of an identifier.
//
@ -119,11 +132,12 @@ static bool starts_with(char *p, char *q) {
static char *read_ident(char *p) {
uint32_t c = decode_utf8(&p, p);
if (!is_ident1(c)) return NULL;
for (;;) {
char *q;
c = decode_utf8(&q, p);
if (!is_ident2(c)) return p;
if (!('a' <= c && c <= 'f') && !is_ident2(c)) {
return p;
}
p = q;
}
}
@ -136,7 +150,6 @@ static int from_hex(char c) {
static bool is_keyword(Token *tok) {
static HashMap map;
if (map.capacity == 0) {
static char *kw[] = {
"return", "if", "else",
@ -155,18 +168,17 @@ static bool is_keyword(Token *tok) {
"typeof", "asm", "_Thread_local",
"__thread", "_Atomic", "__attribute__",
};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
hashmap_put(&map, kw[i], (void *)1);
}
}
return hashmap_get2(&map, tok->loc, tok->len);
}
static int read_escaped_char(char **new_pos, char *p) {
if ('0' <= *p && *p <= '7') {
// Read an octal number.
int c = *p++ - '0';
unsigned c = *p++ - '0';
if ('0' <= *p && *p <= '7') {
c = (c << 3) + (*p++ - '0');
if ('0' <= *p && *p <= '7') c = (c << 3) + (*p++ - '0');
@ -174,20 +186,18 @@ static int read_escaped_char(char **new_pos, char *p) {
*new_pos = p;
return c;
}
if (*p == 'x') {
// Read a hexadecimal number.
p++;
if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence");
int c = 0;
for (; isxdigit(*p); p++) c = (c << 4) + from_hex(*p);
unsigned c = 0;
for (; isxdigit(*p); p++) {
c = (c << 4) + from_hex(*p); /* TODO(jart): overflow here unicode_test */
}
*new_pos = p;
return c;
}
*new_pos = p + 1;
switch (*p) {
case 'a':
return '\a';
@ -225,14 +235,12 @@ static Token *read_string_literal(char *start, char *quote) {
char *end = string_literal_end(quote + 1);
char *buf = calloc(1, end - quote);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\')
buf[len++] = read_escaped_char(&p, p + 1);
else
buf[len++] = *p++;
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty_char, len + 1);
tok->str = buf;
@ -250,13 +258,11 @@ static Token *read_utf16_string_literal(char *start, char *quote) {
char *end = string_literal_end(quote + 1);
uint16_t *buf = calloc(2, end - start - 1);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\') {
buf[len++] = read_escaped_char(&p, p + 1);
continue;
}
uint32_t c = decode_utf8(&p, p);
if (c < 0x10000) {
// Encode a code point in 2 bytes.
@ -268,7 +274,6 @@ static Token *read_utf16_string_literal(char *start, char *quote) {
buf[len++] = 0xdc00 + (c & 0x3ff);
}
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty_ushort, len + 1);
tok->str = (char *)buf;
@ -283,14 +288,12 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
char *end = string_literal_end(quote + 1);
uint32_t *buf = calloc(4, end - quote);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\')
buf[len++] = read_escaped_char(&p, p + 1);
else
buf[len++] = decode_utf8(&p, p);
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty, len + 1);
tok->str = (char *)buf;
@ -300,16 +303,13 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
static Token *read_char_literal(char *start, char *quote, Type *ty) {
char *p = quote + 1;
if (*p == '\0') error_at(start, "unclosed char literal");
int c;
if (*p == '\\')
c = read_escaped_char(&p, p + 1);
else
c = decode_utf8(&p, p);
char *end = strchr(p, '\'');
if (!end) error_at(p, "unclosed char literal");
Token *tok = new_token(TK_NUM, start, end + 1);
tok->val = c;
tok->ty = ty;
@ -318,7 +318,6 @@ static Token *read_char_literal(char *start, char *quote, Type *ty) {
static bool convert_pp_int(Token *tok) {
char *p = tok->loc;
// Read a binary, octal, decimal or hexadecimal number.
int base = 10;
if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) {
@ -330,22 +329,19 @@ static bool convert_pp_int(Token *tok) {
} else if (*p == '0') {
base = 8;
}
int64_t val = strtoul(p, &p, base);
// Read U, L or LL suffixes.
bool l = false;
bool u = false;
if (starts_with(p, "LLU") || starts_with(p, "LLu") || starts_with(p, "llU") ||
starts_with(p, "llu") || starts_with(p, "ULL") || starts_with(p, "Ull") ||
starts_with(p, "uLL") || starts_with(p, "ull")) {
if (LOOKINGAT(p, "LLU") || LOOKINGAT(p, "LLu") || LOOKINGAT(p, "llU") ||
LOOKINGAT(p, "llu") || LOOKINGAT(p, "ULL") || LOOKINGAT(p, "Ull") ||
LOOKINGAT(p, "uLL") || LOOKINGAT(p, "ull")) {
p += 3;
l = u = true;
} else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) {
p += 2;
l = u = true;
} else if (starts_with(p, "LL") || starts_with(p, "ll")) {
} else if (LOOKINGAT(p, "LL") || LOOKINGAT(p, "ll")) {
p += 2;
l = true;
} else if (*p == 'L' || *p == 'l') {
@ -355,9 +351,7 @@ static bool convert_pp_int(Token *tok) {
p++;
u = true;
}
if (p != tok->loc + tok->len) return false;
// Infer a type.
Type *ty;
if (base == 10) {
@ -385,7 +379,6 @@ static bool convert_pp_int(Token *tok) {
else
ty = ty_int;
}
tok->kind = TK_NUM;
tok->val = val;
tok->ty = ty;
@ -402,11 +395,9 @@ static bool convert_pp_int(Token *tok) {
static void convert_pp_number(Token *tok) {
// Try to parse as an integer constant.
if (convert_pp_int(tok)) return;
// If it's not an integer, it must be a floating point constant.
char *end;
long double val = strtold(tok->loc, &end);
Type *ty;
if (*end == 'f' || *end == 'F') {
ty = ty_float;
@ -417,9 +408,7 @@ static void convert_pp_number(Token *tok) {
} else {
ty = ty_double;
}
if (tok->loc + tok->len != end) error_tok(tok, "invalid numeric constant");
tok->kind = TK_NUM;
tok->fval = val;
tok->ty = ty;
@ -438,7 +427,6 @@ void convert_pp_tokens(Token *tok) {
static void add_line_numbers(Token *tok) {
char *p = current_file->contents;
int n = 1;
do {
if (p == tok->loc) {
tok->line_no = n;
@ -461,32 +449,27 @@ Token *tokenize_string_literal(Token *tok, Type *basety) {
// Tokenize a given string and returns new tokens.
Token *tokenize(File *file) {
current_file = file;
char *p = file->contents;
Token head = {};
Token *cur = &head;
at_bol = true;
has_space = false;
while (*p) {
// Skip line comments.
if (starts_with(p, "//")) {
if (LOOKINGAT(p, "//")) {
p += 2;
while (*p != '\n') p++;
has_space = true;
continue;
}
// Skip block comments.
if (starts_with(p, "/*")) {
if (LOOKINGAT(p, "/*")) {
char *q = strstr(p + 2, "*/");
if (!q) error_at(p, "unclosed block comment");
p = q + 2;
has_space = true;
continue;
}
// Skip newline.
if (*p == '\n') {
p++;
@ -494,14 +477,12 @@ Token *tokenize(File *file) {
has_space = false;
continue;
}
// Skip whitespace characters.
if (isspace(*p)) {
if (is_space(*p)) {
p++;
has_space = true;
continue;
}
// Numeric literal
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
char *q = p++;
@ -516,42 +497,36 @@ Token *tokenize(File *file) {
cur = cur->next = new_token(TK_PP_NUM, q, p);
continue;
}
// String literal
if (*p == '"') {
cur = cur->next = read_string_literal(p, p);
p += cur->len;
continue;
}
// UTF-8 string literal
if (starts_with(p, "u8\"")) {
if (LOOKINGAT(p, "u8\"")) {
cur = cur->next = read_string_literal(p, p + 2);
p += cur->len;
continue;
}
// UTF-16 string literal
if (starts_with(p, "u\"")) {
if (LOOKINGAT(p, "u\"")) {
cur = cur->next = read_utf16_string_literal(p, p + 1);
p += cur->len;
continue;
}
// Wide string literal
if (starts_with(p, "L\"")) {
if (LOOKINGAT(p, "L\"")) {
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
p += cur->len;
continue;
}
// UTF-32 string literal
if (starts_with(p, "U\"")) {
if (LOOKINGAT(p, "U\"")) {
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
p += cur->len;
continue;
}
// Character literal
if (*p == '\'') {
cur = cur->next = read_char_literal(p, p, ty_int);
@ -559,29 +534,25 @@ Token *tokenize(File *file) {
p += cur->len;
continue;
}
// UTF-16 character literal
if (starts_with(p, "u'")) {
if (LOOKINGAT(p, "u'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_ushort);
cur->val &= 0xffff;
p += cur->len;
continue;
}
// Wide character literal
if (starts_with(p, "L'")) {
if (LOOKINGAT(p, "L'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_int);
p += cur->len;
continue;
}
// UTF-32 character literal
if (starts_with(p, "U'")) {
if (LOOKINGAT(p, "U'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_uint);
p += cur->len;
continue;
}
// Identifier or keyword
char *q;
if ((q = read_ident(p)) != NULL) {
@ -589,38 +560,32 @@ Token *tokenize(File *file) {
p = q;
continue;
}
// Three-letter punctuators
if (starts_with(p, "<<=") || starts_with(p, ">>=") ||
starts_with(p, "...")) {
if (LOOKINGAT(p, "<<=") || LOOKINGAT(p, ">>=") || LOOKINGAT(p, "...")) {
cur = cur->next = new_token(TK_RESERVED, p, p + 3);
p += 3;
continue;
}
// Two-letter punctuators
if (starts_with(p, "==") || starts_with(p, "!=") || starts_with(p, "<=") ||
starts_with(p, ">=") || starts_with(p, "->") || starts_with(p, "+=") ||
starts_with(p, "-=") || starts_with(p, "*=") || starts_with(p, "/=") ||
starts_with(p, "++") || starts_with(p, "--") || starts_with(p, "%=") ||
starts_with(p, "&=") || starts_with(p, "|=") || starts_with(p, "^=") ||
starts_with(p, "&&") || starts_with(p, "||") || starts_with(p, "<<") ||
starts_with(p, ">>") || starts_with(p, "##")) {
if (LOOKINGAT(p, "==") || LOOKINGAT(p, "!=") || LOOKINGAT(p, "<=") ||
LOOKINGAT(p, ">=") || LOOKINGAT(p, "->") || LOOKINGAT(p, "+=") ||
LOOKINGAT(p, "-=") || LOOKINGAT(p, "*=") || LOOKINGAT(p, "/=") ||
LOOKINGAT(p, "++") || LOOKINGAT(p, "--") || LOOKINGAT(p, "%=") ||
LOOKINGAT(p, "&=") || LOOKINGAT(p, "|=") || LOOKINGAT(p, "^=") ||
LOOKINGAT(p, "&&") || LOOKINGAT(p, "||") || LOOKINGAT(p, "<<") ||
LOOKINGAT(p, ">>") || LOOKINGAT(p, "##")) {
cur = cur->next = new_token(TK_RESERVED, p, p + 2);
p += 2;
continue;
}
// Single-letter punctuators
if (ispunct(*p)) {
cur = cur->next = new_token(TK_RESERVED, p, p + 1);
p++;
continue;
}
error_at(p, "invalid token");
}
cur = cur->next = new_token(TK_EOF, p, p);
add_line_numbers(head.next);
return head.next;
@ -629,7 +594,6 @@ Token *tokenize(File *file) {
// Returns the contents of a given file.
static char *read_file(char *path) {
FILE *fp;
if (strcmp(path, "-") == 0) {
// By convention, read from stdin if a given filename is "-".
fp = stdin;
@ -637,11 +601,9 @@ static char *read_file(char *path) {
fp = fopen(path, "r");
if (!fp) return NULL;
}
int buflen = 4096;
int nread = 0;
char *buf = calloc(1, buflen);
// Read the entire file.
for (;;) {
int end = buflen - 2; // extra 2 bytes for the trailing "\n\0"
@ -653,15 +615,12 @@ static char *read_file(char *path) {
buf = realloc(buf, buflen);
}
}
if (fp != stdin) fclose(fp);
// Make sure that the last logical line is properly terminated with '\n'.
if (nread > 0 && buf[nread - 1] == '\\')
buf[nread - 1] = '\n';
else if (nread == 0 || buf[nread - 1] != '\n')
buf[nread++] = '\n';
buf[nread] = '\0';
return buf;
}
@ -682,7 +641,6 @@ File *new_file(char *name, int file_no, char *contents) {
// Replaces \r or \r\n with \n.
static void canonicalize_newline(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '\r' && p[i + 1] == '\n') {
i += 2;
@ -694,19 +652,16 @@ static void canonicalize_newline(char *p) {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
// Removes backslashes followed by a newline.
static void remove_backslash_newline(char *p) {
int i = 0, j = 0;
// We want to keep the number of newline characters so that
// the logical line number matches the physical one.
// This counter maintain the number of newlines we have removed.
int n = 0;
while (p[i]) {
if (p[i] == '\\' && p[i + 1] == '\n') {
i += 2;
@ -718,7 +673,6 @@ static void remove_backslash_newline(char *p) {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
@ -734,9 +688,8 @@ static uint32_t read_universal_char(char *p, int len) {
// Replace \u or \U escape sequences with corresponding UTF-8 bytes.
static void convert_universal_chars(char *p) {
char *q = p;
while (*p) {
if (starts_with(p, "\\u")) {
if (LOOKINGAT(p, "\\u")) {
uint32_t c = read_universal_char(p + 2, 4);
if (c) {
p += 6;
@ -744,7 +697,7 @@ static void convert_universal_chars(char *p) {
} else {
*q++ = *p++;
}
} else if (starts_with(p, "\\U")) {
} else if (LOOKINGAT(p, "\\U")) {
uint32_t c = read_universal_char(p + 2, 8);
if (c) {
p += 10;
@ -759,27 +712,22 @@ static void convert_universal_chars(char *p) {
*q++ = *p++;
}
}
*q = '\0';
}
Token *tokenize_file(char *path) {
char *p = read_file(path);
if (!p) return NULL;
canonicalize_newline(p);
remove_backslash_newline(p);
convert_universal_chars(p);
// Save the filename for assembler .file directive.
static int file_no;
File *file = new_file(path, file_no + 1, p);
// Save the filename for assembler .file directive.
input_files = realloc(input_files, sizeof(char *) * (file_no + 2));
input_files[file_no] = file;
input_files[file_no + 1] = NULL;
file_no++;
return tokenize(file);
}

View file

@ -1,21 +1,21 @@
#include "third_party/chibicc/chibicc.h"
Type *ty_void = &(Type){TY_VOID, 1, 1};
Type *ty_bool = &(Type){TY_BOOL, 1, 1};
Type *ty_char = &(Type){TY_CHAR, 1, 1};
Type *ty_short = &(Type){TY_SHORT, 2, 2};
Type *ty_int = &(Type){TY_INT, 4, 4};
Type *ty_long = &(Type){TY_LONG, 8, 8};
Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
Type *ty_uint = &(Type){TY_INT, 4, 4, true};
Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
Type *ty_float = &(Type){TY_FLOAT, 4, 4};
Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
/* TODO(jart): Why can't these be const? */
Type ty_void[1] = {{TY_VOID, 1, 1}};
Type ty_bool[1] = {{TY_BOOL, 1, 1}};
Type ty_char[1] = {{TY_CHAR, 1, 1}};
Type ty_short[1] = {{TY_SHORT, 2, 2}};
Type ty_int[1] = {{TY_INT, 4, 4}};
Type ty_long[1] = {{TY_LONG, 8, 8}};
Type ty_int128[1] = {{TY_INT128, 16, 16}};
Type ty_uchar[1] = {{TY_CHAR, 1, 1, true}};
Type ty_ushort[1] = {{TY_SHORT, 2, 2, true}};
Type ty_uint[1] = {{TY_INT, 4, 4, true}};
Type ty_ulong[1] = {{TY_LONG, 8, 8, true}};
Type ty_uint128[1] = {{TY_INT128, 16, 16, true}};
Type ty_float[1] = {{TY_FLOAT, 4, 4}};
Type ty_double[1] = {{TY_DOUBLE, 8, 8}};
Type ty_ldouble[1] = {{TY_LDOUBLE, 16, 16}};
static Type *new_type(TypeKind kind, int size, int align) {
Type *ty = calloc(1, sizeof(Type));
@ -28,7 +28,7 @@ static Type *new_type(TypeKind kind, int size, int align) {
bool is_integer(Type *ty) {
TypeKind k = ty->kind;
return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || k == TY_INT ||
k == TY_LONG || k == TY_ENUM;
k == TY_LONG || k == TY_INT128 || k == TY_ENUM;
}
bool is_flonum(Type *ty) {
@ -42,18 +42,15 @@ bool is_numeric(Type *ty) {
bool is_compatible(Type *t1, Type *t2) {
if (t1 == t2) return true;
if (t1->origin) return is_compatible(t1->origin, t2);
if (t2->origin) return is_compatible(t1, t2->origin);
if (t1->kind != t2->kind) return false;
switch (t1->kind) {
case TY_CHAR:
case TY_SHORT:
case TY_INT:
case TY_LONG:
case TY_INT128:
return t1->is_unsigned == t2->is_unsigned;
case TY_FLOAT:
case TY_DOUBLE:
@ -64,11 +61,11 @@ bool is_compatible(Type *t1, Type *t2) {
case TY_FUNC: {
if (!is_compatible(t1->return_ty, t2->return_ty)) return false;
if (t1->is_variadic != t2->is_variadic) return false;
Type *p1 = t1->params;
Type *p2 = t2->params;
for (; p1 && p2; p1 = p1->next, p2 = p2->next)
for (; p1 && p2; p1 = p1->next, p2 = p2->next) {
if (!is_compatible(p1, p2)) return false;
}
return p1 == NULL && p2 == NULL;
}
case TY_ARRAY:
@ -125,19 +122,14 @@ Type *struct_type(void) {
static Type *get_common_type(Type *ty1, Type *ty2) {
if (ty1->base) return pointer_to(ty1->base);
if (ty1->kind == TY_FUNC) return pointer_to(ty1);
if (ty2->kind == TY_FUNC) return pointer_to(ty2);
if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE) return ty_ldouble;
if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) return ty_double;
if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) return ty_float;
if (ty1->size < 4) ty1 = ty_int;
if (ty2->size < 4) ty2 = ty_int;
if (ty1->size != ty2->size) return (ty1->size < ty2->size) ? ty2 : ty1;
if (ty2->is_unsigned) return ty2;
return ty1;
}
@ -157,7 +149,6 @@ static void usual_arith_conv(Node **lhs, Node **rhs) {
void add_type(Node *node) {
if (!node || node->ty) return;
add_type(node->lhs);
add_type(node->rhs);
add_type(node->cond);
@ -165,10 +156,8 @@ void add_type(Node *node) {
add_type(node->els);
add_type(node->init);
add_type(node->inc);
for (Node *n = node->body; n; n = n->next) add_type(n);
for (Node *n = node->args; n; n = n->next) add_type(n);
switch (node->kind) {
case ND_NUM:
node->ty = ty_int;
@ -192,7 +181,7 @@ void add_type(Node *node) {
}
case ND_ASSIGN:
if (node->lhs->ty->kind == TY_ARRAY)
error_tok(node->lhs->tok, "not an lvalue");
error_tok(node->lhs->tok, "not an lvalue!");
if (node->lhs->ty->kind != TY_STRUCT)
node->rhs = new_cast(node->rhs, node->lhs->ty);
node->ty = node->lhs->ty;
@ -244,12 +233,20 @@ void add_type(Node *node) {
return;
}
case ND_DEREF:
#if 0
if (node->lhs->ty->size == 16 && (node->lhs->ty->kind == TY_FLOAT ||
node->lhs->ty->kind == TY_DOUBLE)) {
node->ty = node->lhs->ty;
} else {
#endif
if (!node->lhs->ty->base)
error_tok(node->tok, "invalid pointer dereference");
if (node->lhs->ty->base->kind == TY_VOID)
error_tok(node->tok, "dereferencing a void pointer");
node->ty = node->lhs->ty->base;
#if 0
}
#endif
return;
case ND_STMT_EXPR:
if (node->body) {
@ -271,7 +268,6 @@ void add_type(Node *node) {
add_type(node->cas_old);
add_type(node->cas_new);
node->ty = ty_bool;
if (node->cas_addr->ty->kind != TY_PTR)
error_tok(node->cas_addr->tok, "pointer expected");
if (node->cas_old->ty->kind != TY_PTR)

View file

@ -6,20 +6,17 @@ int encode_utf8(char *buf, uint32_t c) {
buf[0] = c;
return 1;
}
if (c <= 0x7FF) {
buf[0] = 0b11000000 | (c >> 6);
buf[1] = 0b10000000 | (c & 0b00111111);
return 2;
}
if (c <= 0xFFFF) {
buf[0] = 0b11100000 | (c >> 12);
buf[1] = 0b10000000 | ((c >> 6) & 0b00111111);
buf[2] = 0b10000000 | (c & 0b00111111);
return 3;
}
buf[0] = 0b11110000 | (c >> 18);
buf[1] = 0b10000000 | ((c >> 12) & 0b00111111);
buf[2] = 0b10000000 | ((c >> 6) & 0b00111111);
@ -39,11 +36,9 @@ uint32_t decode_utf8(char **new_pos, char *p) {
*new_pos = p + 1;
return *p;
}
char *start = p;
int len;
uint32_t c;
if ((unsigned char)*p >= 0b11110000) {
len = 4;
c = *p & 0b111;
@ -56,13 +51,11 @@ uint32_t decode_utf8(char **new_pos, char *p) {
} else {
error_at(start, "invalid UTF-8 sequence");
}
for (int i = 1; i < len; i++) {
if ((unsigned char)p[i] >> 6 != 0b10)
error_at(start, "invalid UTF-8 sequence");
c = (c << 6) | (p[i] & 0b111111);
}
*new_pos = p + len;
return c;
}
@ -85,7 +78,7 @@ static bool in_range(uint32_t *range, uint32_t c) {
// (U+3000, full-width space) are allowed because they are out of range.
bool is_ident1(uint32_t c) {
static uint32_t range[] = {
'_', '_', 'a', 'z', 'A', 'Z', '$', '$',
'a', 'z', 'A', 'Z', '_', '_', '$', '$',
0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
@ -100,7 +93,6 @@ bool is_ident1(uint32_t c) {
0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD,
0xE0000, 0xEFFFD, -1,
};
return in_range(range, c);
}
@ -111,68 +103,9 @@ bool is_ident2(uint32_t c) {
'0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0,
0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1,
};
return is_ident1(c) || in_range(range, c);
}
// Returns the number of columns needed to display a given
// character in a fixed-width font.
//
// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
static int char_width(uint32_t c) {
static uint32_t range1[] = {
0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,
0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,
0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,
0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,
0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,
0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,
0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,
0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,
0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,
0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,
0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,
0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,
0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,
0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,
0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,
0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,
0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,
0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,
0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,
0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,
0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,
0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,
0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,
0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,
0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,
0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,
0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,
0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,
0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,
0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,
0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,
0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,
0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,
0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,
0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
-1,
};
if (in_range(range1, c)) return 0;
static uint32_t range2[] = {
0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,
0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1,
};
if (in_range(range2, c)) return 2;
return 1;
}
// Returns the number of columns needed to display a given
// string in a fixed-width font.
int str_width(char *p, int len) {
@ -180,7 +113,7 @@ int str_width(char *p, int len) {
int w = 0;
while (p - start < len) {
uint32_t c = decode_utf8(&p, p);
w += char_width(c);
w += wcwidth(c);
}
return w;
}

View file

@ -26,7 +26,7 @@
/* #define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__) */
noreturn void __compilerrt_abort_impl(const char *file, int line,
wontreturn void __compilerrt_abort_impl(const char *file, int line,
const char *function);
#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)

View file

@ -34,7 +34,7 @@ struct MallocParams g_mparams;
* Note that contiguous allocations are what Doug Lea recommends.
*/
static void *dlmalloc_requires_more_vespene_gas(size_t size) {
if (0 && !IsTrustworthy()) {
if (0) {
size_t need = mallinfo().arena + size;
if (need > 8 * 1024 * 1024) {
struct sysinfo info;

View file

@ -1,33 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.source __FILE__
/ Avoid dtoa needing .data section.
.bss
.align 4
dtoa_divmax:
.zero 4
.endobj dtoa_divmax,globl
.previous
.init.start 202,_init_dtoa_divmax
movb $2,dtoa_divmax(%rip)
.init.end 202,_init_dtoa_divmax

5848
third_party/dtoa/dtoa.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_
#define COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *g_fmt(char *buf /*[32]*/, double x);
char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign,
char **rve) nodiscard;
void freedtoa(char *s);
char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign,
char **rve, char *buf, size_t blen);
double strtod(const char *, char **);
double plan9_strtod(const char *, char **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_ */

View file

@ -1,62 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_DTOA
THIRD_PARTY_DTOA_ARTIFACTS += THIRD_PARTY_DTOA_A
THIRD_PARTY_DTOA = $(THIRD_PARTY_DTOA_A_DEPS) $(THIRD_PARTY_DTOA_A)
THIRD_PARTY_DTOA_A = o/$(MODE)/third_party/dtoa/dtoa.a
THIRD_PARTY_DTOA_A_FILES := $(wildcard third_party/dtoa/*)
THIRD_PARTY_DTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_DTOA_A_FILES))
THIRD_PARTY_DTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_DTOA_A_FILES))
THIRD_PARTY_DTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_DTOA_A_FILES))
THIRD_PARTY_DTOA_A_SRCS = \
$(THIRD_PARTY_DTOA_A_SRCS_S) \
$(THIRD_PARTY_DTOA_A_SRCS_C)
THIRD_PARTY_DTOA_A_OBJS = \
$(THIRD_PARTY_DTOA_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_DTOA_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(THIRD_PARTY_DTOA_A_SRCS_C:%.c=o/$(MODE)/%.o)
THIRD_PARTY_DTOA_A_CHECKS = \
$(THIRD_PARTY_DTOA_A).pkg \
$(THIRD_PARTY_DTOA_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_DTOA_A_DIRECTDEPS = \
LIBC_TINYMATH \
LIBC_STR \
LIBC_STUBS \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_SYSV
THIRD_PARTY_DTOA_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_DTOA_A): \
third_party/dtoa/ \
$(THIRD_PARTY_DTOA_A).pkg \
$(THIRD_PARTY_DTOA_A_OBJS)
$(THIRD_PARTY_DTOA_A).pkg: \
$(THIRD_PARTY_DTOA_A_OBJS) \
$(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_DTOA_A_OBJS): \
OVERRIDE_CFLAGS += \
$(OLD_CODE) \
$(IEEE_MATH) \
-ffunction-sections \
-fdata-sections
THIRD_PARTY_DTOA_LIBS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)))
THIRD_PARTY_DTOA_SRCS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_DTOA_HDRS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_DTOA_CHECKS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_DTOA_OBJS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_OBJS))
$(THIRD_PARTY_DTOA_OBJS): $(BUILD_FILES) third_party/dtoa/dtoa.mk
.PHONY: o/$(MODE)/third_party/dtoa
o/$(MODE)/third_party/dtoa: $(THIRD_PARTY_DTOA_CHECKS)

View file

@ -1,114 +0,0 @@
#pragma GCC diagnostic ignored "-Wparentheses"
#pragma GCC diagnostic ignored "-Wunused-label"
asm(".ident\t\"\\n\\n\
dtoa (MIT License)\\n\
The author of this software is David M. Gay.\\n\
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\"");
asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */
/****************************************************************
*
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 1996 by Lucent Technologies.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*
***************************************************************/
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
* it suffices to declare buf
* char buf[32];
*/
#ifdef __cplusplus
extern "C" {
#endif
extern char *dtoa(double, int, int, int *, int *, char **);
extern char *g_fmt(char *, double);
extern void freedtoa(char*);
#ifdef __cplusplus
}
#endif
char *
g_fmt(register char *b, double x)
{
register int i, k;
register char *s;
int decpt, j, sign;
char *b0, *s0, *se;
b0 = b;
#ifdef IGNORE_ZERO_SIGN
if (!x) {
*b++ = '0';
*b = 0;
goto done;
}
#endif
s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
if (sign)
*b++ = '-';
if (decpt == 9999) /* Infinity or Nan */ {
while(*b++ = *s++);
goto done0;
}
if (decpt <= -4 || decpt > se - s + 5) {
*b++ = *s++;
if (*s) {
*b++ = '.';
while(*b = *s++)
b++;
}
*b++ = 'e';
/* sprintf(b, "%+.2d", decpt - 1); */
if (--decpt < 0) {
*b++ = '-';
decpt = -decpt;
}
else
*b++ = '+';
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
for(;;) {
i = decpt / k;
*b++ = i + '0';
if (--j <= 0)
break;
decpt -= i*k;
decpt *= 10;
}
*b = 0;
}
else if (decpt <= 0) {
*b++ = '.';
for(; decpt < 0; decpt++)
*b++ = '0';
while(*b++ = *s++);
}
else {
while(*b = *s++) {
b++;
if (--decpt == 0 && *s)
*b++ = '.';
}
for(; decpt > 0; decpt--)
*b++ = '0';
*b = 0;
}
done0:
freedtoa(s0);
done:
return b0;
}

View file

@ -1,531 +0,0 @@
#include "libc/macros.h"
#include "libc/str/str.h"
#include "third_party/dtoa/dtoa.h"
/**
* @fileoverview Plan 9 strtod().
* It's like dtoa but smaller.
*/
asm(".ident\t\"\\n\\n\
Plan 9 » strtod (MIT)\\n\
The authors of this software are Rob Pike and Ken Thompson.\\n\
Copyright (c) 2002 by Lucent Technologies.\"");
asm(".include \"libc/disclaimer.inc\"");
#define nelem(a) ARRAYLEN(a)
#define ulong unsigned long
#define nil NULL
#define __NaN() __builtin_nanf("")
/* clang-format off */
/* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include "libc/str/str.h"
#include "libc/math.h"
#include "libc/sysv/errfuns.h"
static ulong
umuldiv(ulong a, ulong b, ulong c)
{
double d;
d = ((double)a * (double)b) / (double)c;
if(d >= 4294967295.)
d = 4294967295.;
return (ulong)d;
}
/*
* This routine will convert to arbitrary precision
* floating point entirely in multi-precision fixed.
* The answer is the closest floating point number to
* the given decimal number. Exactly half way are
* rounded ala ieee rules.
* Method is to scale input decimal between .500 and .999...
* with external power of 2, then binary search for the
* closest mantissa to this decimal number.
* Nmant is is the required precision. (53 for ieee dp)
* Nbits is the max number of bits/word. (must be <= 28)
* Prec is calculated - the number of words of fixed mantissa.
*/
enum
{
Nbits = 28, /* bits safely represented in a ulong */
Nmant = 53, /* bits of precision required */
Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
Ndig = 1500,
One = (ulong)(1<<Nbits),
Half = (ulong)(One>>1),
Maxe = 310,
Fsign = 1<<0, /* found - */
Fesign = 1<<1, /* found e- */
Fdpoint = 1<<2, /* found . */
S0 = 0, /* _ _S0 +S1 #S2 .S3 */
S1, /* _+ #S2 .S3 */
S2, /* _+# #S2 .S4 eS5 */
S3, /* _+. #S4 */
S4, /* _+#.# #S4 eS5 */
S5, /* _+#.#e +S6 #S7 */
S6, /* _+#.#e+ #S7 */
S7 /* _+#.#e+# #S7 */
};
static int fpcmp(char*, ulong*);
static void frnorm(ulong*);
static void divascii(char*, int*, int*, int*);
static void mulascii(char*, int*, int*, int*);
typedef struct Tab Tab;
struct Tab
{
int bp;
int siz;
char* cmp;
};
double
plan9_strtod(const char *as, char **aas)
{
int na, ex, dp, bp, c, i, flag, state;
ulong low[Prec], hig[Prec], mid[Prec];
double d;
char *s, a[Ndig];
flag = 0; /* Fsign, Fesign, Fdpoint */
na = 0; /* number of digits of a[] */
dp = 0; /* na of decimal point */
ex = 0; /* exonent */
state = S0;
for(s=(char*)as;; s++) {
c = *s;
if(c >= '0' && c <= '9') {
switch(state) {
case S0:
case S1:
case S2:
state = S2;
break;
case S3:
case S4:
state = S4;
break;
case S5:
case S6:
case S7:
state = S7;
ex = ex*10 + (c-'0');
continue;
}
if(na == 0 && c == '0') {
dp--;
continue;
}
if(na < Ndig-50)
a[na++] = c;
continue;
}
switch(c) {
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
if(state == S0)
continue;
break;
case '-':
if(state == S0)
flag |= Fsign;
else
flag |= Fesign;
case '+':
if(state == S0)
state = S1;
else
if(state == S5)
state = S6;
else
break; /* syntax */
continue;
case '.':
flag |= Fdpoint;
dp = na;
if(state == S0 || state == S1) {
state = S3;
continue;
}
if(state == S2) {
state = S4;
continue;
}
break;
case 'e':
case 'E':
if(state == S2 || state == S4) {
state = S5;
continue;
}
break;
}
break;
}
/*
* clean up return char-pointer
*/
switch(state) {
case S0:
if(strcasecmp(s, "nan") == 0) {
if(aas != nil)
*aas = s+3;
goto retnan;
}
case S1:
if(strcasecmp(s, "infinity") == 0) {
if(aas != nil)
*aas = s+8;
goto retinf;
}
if(strcasecmp(s, "inf") == 0) {
if(aas != nil)
*aas = s+3;
goto retinf;
}
case S3:
if(aas != nil)
*aas = (char*)as;
goto ret0; /* no digits found */
case S6:
s--; /* back over +- */
case S5:
s--; /* back over e */
break;
}
if(aas != nil)
*aas = s;
if(flag & Fdpoint)
while(na > 0 && a[na-1] == '0')
na--;
if(na == 0)
goto ret0; /* zero */
a[na] = 0;
if(!(flag & Fdpoint))
dp = na;
if(flag & Fesign)
ex = -ex;
dp += ex;
if(dp < -Maxe){
erange();
goto ret0; /* underflow by exp */
} else
if(dp > +Maxe)
goto retinf; /* overflow by exp */
/*
* normalize the decimal ascii number
* to range .[5-9][0-9]* e0
*/
bp = 0; /* binary exponent */
while(dp > 0)
divascii(a, &na, &dp, &bp);
while(dp < 0 || a[0] < '5')
mulascii(a, &na, &dp, &bp);
/* close approx by naïve conversion */
mid[0] = 0;
mid[1] = 1;
for(i=0; (c=a[i]) != '\0'; i++) {
mid[0] = mid[0]*10 + (c-'0');
mid[1] = mid[1]*10;
if(i >= 8)
break;
}
low[0] = umuldiv(mid[0], One, mid[1]);
hig[0] = umuldiv(mid[0]+1, One, mid[1]);
for(i=1; i<Prec; i++) {
low[i] = 0;
hig[i] = One-1;
}
/* binary search for closest mantissa */
for(;;) {
/* mid = (hig + low) / 2 */
c = 0;
for(i=0; i<Prec; i++) {
mid[i] = hig[i] + low[i];
if(c)
mid[i] += One;
c = mid[i] & 1;
mid[i] >>= 1;
}
frnorm(mid);
/* compare */
c = fpcmp(a, mid);
if(c > 0) {
c = 1;
for(i=0; i<Prec; i++)
if(low[i] != mid[i]) {
c = 0;
low[i] = mid[i];
}
if(c)
break; /* between mid and hig */
continue;
}
if(c < 0) {
for(i=0; i<Prec; i++)
hig[i] = mid[i];
continue;
}
/* only hard part is if even/odd roundings wants to go up */
c = mid[Prec-1] & (Sigbit-1);
if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
mid[Prec-1] -= c;
break; /* exactly mid */
}
/* normal rounding applies */
c = mid[Prec-1] & (Sigbit-1);
mid[Prec-1] -= c;
if(c >= Sigbit/2) {
mid[Prec-1] += Sigbit;
frnorm(mid);
}
goto out;
ret0:
return 0;
retnan:
return __NaN();
retinf:
/*
* Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
erange();
if(flag & Fsign)
return -HUGE_VAL;
return HUGE_VAL;
out:
d = 0;
for(i=0; i<Prec; i++)
d = d*One + mid[i];
if(flag & Fsign)
d = -d;
d = ldexp(d, bp - Prec*Nbits);
if(d == 0){ /* underflow */
erange();
}
return d;
}
static void
frnorm(ulong *f)
{
int i, c;
c = 0;
for(i=Prec-1; i>0; i--) {
f[i] += c;
c = f[i] >> Nbits;
f[i] &= One-1;
}
f[0] += c;
}
static int
fpcmp(char *a, ulong* f)
{
ulong tf[Prec];
int i, d, c;
for(i=0; i<Prec; i++)
tf[i] = f[i];
for(;;) {
/* tf *= 10 */
for(i=0; i<Prec; i++)
tf[i] = tf[i]*10;
frnorm(tf);
d = (tf[0] >> Nbits) + '0';
tf[0] &= One-1;
/* compare next digit */
c = *a;
if(c == 0) {
if('0' < d)
return -1;
if(tf[0] != 0)
goto cont;
for(i=1; i<Prec; i++)
if(tf[i] != 0)
goto cont;
return 0;
}
if(c > d)
return +1;
if(c < d)
return -1;
a++;
cont:;
}
}
static void
divby(char *a, int *na, int b)
{
int n, c;
char *p;
p = a;
n = 0;
while(n>>b == 0) {
c = *a++;
if(c == 0) {
while(n) {
c = n*10;
if(c>>b)
break;
n = c;
}
goto xx;
}
n = n*10 + c-'0';
(*na)--;
}
for(;;) {
c = n>>b;
n -= c<<b;
*p++ = c + '0';
c = *a++;
if(c == 0)
break;
n = n*10 + c-'0';
}
(*na)++;
xx:
while(n) {
n = n*10;
c = n>>b;
n -= c<<b;
*p++ = c + '0';
(*na)++;
}
*p = 0;
}
static Tab tab1[] =
{
{ 1, 0, ""},
{ 3, 1, "7"},
{ 6, 2, "63"},
{ 9, 3, "511"},
{13, 4, "8191"},
{16, 5, "65535"},
{19, 6, "524287"},
{23, 7, "8388607"},
{26, 8, "67108863"},
{27, 9, "134217727"},
};
static void
divascii(char *a, int *na, int *dp, int *bp)
{
int b, d;
Tab *t;
d = *dp;
if(d >= (int)(nelem(tab1)))
d = (int)(nelem(tab1))-1;
t = tab1 + d;
b = t->bp;
if(memcmp(a, t->cmp, t->siz) > 0)
d--;
*dp -= d;
*bp += b;
divby(a, na, b);
}
static void
mulby(char *a, char *p, char *q, int b)
{
int n, c;
n = 0;
*p = 0;
for(;;) {
q--;
if(q < a)
break;
c = *q - '0';
c = (c<<b) + n;
n = c/10;
c -= n*10;
p--;
*p = c + '0';
}
while(n) {
c = n;
n = c/10;
c -= n*10;
p--;
*p = c + '0';
}
}
static Tab tab2[] =
{
{ 1, 1, ""}, /* dp = 0-0 */
{ 3, 3, "125"},
{ 6, 5, "15625"},
{ 9, 7, "1953125"},
{13, 10, "1220703125"},
{16, 12, "152587890625"},
{19, 14, "19073486328125"},
{23, 17, "11920928955078125"},
{26, 19, "1490116119384765625"},
{27, 19, "7450580596923828125"}, /* dp 8-9 */
};
static void
mulascii(char *a, int *na, int *dp, int *bp)
{
char *p;
int d, b;
Tab *t;
d = -*dp;
if(d >= (int)(nelem(tab2)))
d = (int)(nelem(tab2))-1;
t = tab2 + d;
b = t->bp;
if(memcmp(a, t->cmp, t->siz) < 0)
d--;
p = a + *na;
*bp -= b;
*dp += d;
*na += d;
mulby(a, p+d, p, b);
}

View file

@ -786,7 +786,7 @@
* Disabled temporarily in GCC 5+ because of an unresolved noreturn-related
* issue: https://github.com/svaarala/duktape/issues/2155.
*/
#define DUK_NORETURN(decl) decl noreturn
#define DUK_NORETURN(decl) decl wontreturn
#endif
#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L)

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -5,8 +5,9 @@
asm(".ident\t\"\\n\\n\
gdtoa (MIT License)\\n\
The author of this software is David M. Gay.\\n\
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\"");
The author of this software is David M. Gay\\n\
Kudos go to Guy L. Steele, Jr. and Jon L. White\\n\
Copyright (C) 1997, 1998, 2000 by Lucent Technologies\"");
asm(".include \"libc/disclaimer.inc\"");
#define IEEE_8087 1

View file

@ -1,5 +1,5 @@
#include "libc/errno.h"
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

View file

@ -1,4 +1,4 @@
#include "third_party/gdtoa/gdtoaimp.h"
#include "third_party/gdtoa/gdtoa.internal.h"
/* clang-format off */
/****************************************************************

Some files were not shown because too many files have changed in this diff Show more