Enhance chibicc

This commit is contained in:
Justine Tunney
2020-12-09 04:00:48 -08:00
parent 8da931a7f6
commit 9df2cef4c4
52 changed files with 2606 additions and 2004 deletions

View File

@ -6,21 +6,30 @@ which is great, considering it's a 220kb αcτµαlly pδrταblε εxεcµταb
local enhancements
- support __asm__
- support dce
- support gnu asm
- support __int128
- support _Static_assert
- support __vector_size__
- support __builtin_memcpy
- support __builtin_add_overflow, etc.
- support __builtin_memcpy, strlen, strpbrk, etc.
- support __builtin_constant_p, __builtin_likely, etc.
- support __builtin_isunordered, __builtin_islessgreater, etc.
- support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc.
- support __constructor__, __destructor__, __section__, __cold__, etc.
- support __constructor__, __section__, __cold__, -ffunction-sections, etc.
- support building -x assembler-with-cpp a.k.a. .S files
- support profiling w/ -mcount / -mfentry / -mnop-mcount
- improve error messages to trace macro expansions
- reduce #lines of generated assembly by a third
- reduce #bytes of generated binary by a third
local bug fixes
- allow casted values to be lvalues
- permit parentheses around string-initializer
- fix 64-bit bug in generated code for struct bitfields
- fix bug where last statement in statement expression couldn't have label
- print_tokens (chibicc -E) now works in the case of adjacent string literals
local changes

View File

@ -40,7 +40,7 @@ static void DecodeAsmConstraints(AsmOperand *op) {
switch ((c = op->str[i++])) {
case '\0':
case ',': // alternative group
return;
return; // todo: read combos
case '0':
case '1':
case '2':
@ -180,13 +180,17 @@ static bool IsLvalue(AsmOperand *op) {
}
}
static bool CanUseReg(Node *n) {
return is_integer(n->ty) || n->ty->kind == TY_PTR;
static bool CanUseReg(Node **n) {
if ((*n)->ty->kind == TY_ARRAY) {
*n = new_cast(*n, pointer_to((*n)->ty->base));
return true;
}
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 ||
return n->ty->vector_size == 16 || n->ty->kind == TY_FLOAT ||
n->ty->kind == TY_DOUBLE || n->ty->kind == TY_PTR ||
(n->ty->kind == TY_ARRAY && n->ty->size == 16);
}
@ -201,7 +205,7 @@ static int PickAsmReferenceType(AsmOperand *op, AsmOperand *ref) {
case kAsmMem:
error_tok(op->tok, "bad reference");
case kAsmReg:
if (!CanUseReg(op->node)) {
if (!CanUseReg(&op->node)) {
error_tok(op->tok, "expected integral expression");
}
op->regmask = 0;
@ -235,7 +239,7 @@ static int PickAsmOperandType(Asm *a, AsmOperand *op) {
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 & kAsmReg) && CanUseReg(&op->node)) return kAsmReg;
if (op->type & kAsmFlag) return kAsmFlag;
if (op->type & kAsmRaw) return kAsmRaw;
error_tok(op->tok, "constraint mismatch");
@ -245,7 +249,7 @@ static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) {
int i;
op->tok = tok;
op->str = ConsumeStringLiteral(&tok, tok);
tok = skip(tok, "(");
tok = skip(tok, '(');
op->node = expr(&tok, tok);
add_type(op->node);
DecodeAsmConstraints(op);
@ -255,7 +259,7 @@ static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) {
} else {
op->type = PickAsmOperandType(a, op);
}
return skip(tok, ")");
return skip(tok, ')');
}
static Token *ParseAsmOperands(Asm *a, Token *tok) {
@ -267,7 +271,7 @@ static Token *ParseAsmOperands(Asm *a, Token *tok) {
tok = ParseAsmOperand(a, &a->ops[a->n], tok);
++a->n;
if (!EQUAL(tok, ",")) break;
tok = skip(tok, ",");
tok = skip(tok, ',');
}
return tok;
}
@ -315,10 +319,6 @@ static void PickAsmRegisters(Asm *a) {
}
}
}
for (i = 0; i < a->n; ++i) {
assert(!a->ops[i].regmask);
assert(!a->ops[i].x87mask);
}
}
static void MarkUsedAsmOperands(Asm *a) {
@ -378,11 +378,13 @@ static Token *ParseAsmClobbers(Asm *a, Token *tok) {
i = s[3] - '0';
i &= 7;
a->x87clob |= 1 << i;
} else if (!strcmp(s, "memory")) {
/* do nothing */
} else {
error_tok(stok, "unknown clobber register");
}
if (!EQUAL(tok, ",")) break;
tok = skip(tok, ",");
tok = skip(tok, ',');
}
return tok;
}
@ -402,25 +404,25 @@ 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, "(");
tok = skip(tok, '(');
a->tok = tok;
a->str = ConsumeStringLiteral(&tok, tok);
if (!EQUAL(tok, ")")) {
a->isgnu = true;
tok = skip(tok, ":");
tok = skip(tok, ':');
tok = ParseAsmOperands(a, tok);
if (!EQUAL(tok, ")")) {
tok = skip(tok, ":");
tok = skip(tok, ':');
tok = ParseAsmOperands(a, tok);
if (!EQUAL(tok, ")")) {
tok = skip(tok, ":");
tok = skip(tok, ':');
tok = ParseAsmClobbers(a, tok);
}
}
}
PickAsmRegisters(a);
MarkUsedAsmOperands(a);
*rest = skip(tok, ")");
*rest = skip(tok, ')');
return a;
}
@ -541,24 +543,26 @@ static char *HandleAsmSpecifier(Asm *a, char *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;
if (*a->str) {
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);
}
} else {
println("\t%s", a->str);
}
}
@ -668,9 +672,9 @@ static void StoreAsmOutputs(Asm *a) {
println("\tset%s\t(%%rax)", a->ops[i].str + a->ops[i].predicate);
break;
case kAsmReg:
z = bsr(a->ops[i].node->ty->size);
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 {
@ -678,7 +682,7 @@ static void StoreAsmOutputs(Asm *a) {
push();
pop("%rbx");
gen_addr(a->ops[i].node);
println("\tmov\t%%rbx,(%%rax)");
println("\tmov\t%%%s,(%%rax)", kGreg[z][3]);
println("\tpop\t%%rbx");
}
break;

View File

@ -150,8 +150,9 @@ static int getTypeId(Type *ty) {
return F64;
case TY_LDOUBLE:
return F80;
default:
return U64;
}
return U64;
}
void gen_cast(Type *from, Type *to) {

View File

@ -16,15 +16,21 @@ typedef enum {
FILE_DSO,
} FileType;
bool opt_fcommon = true;
bool opt_fpic;
bool opt_verbose;
bool opt_mpopcnt;
bool opt_common = true;
bool opt_data_sections;
bool opt_fentry;
bool opt_function_sections;
bool opt_no_builtin;
bool opt_nop_mcount;
bool opt_pg;
bool opt_mfentry;
bool opt_mnop_mcount;
bool opt_mrecord_mcount;
bool opt_pic;
bool opt_popcnt;
bool opt_record_mcount;
bool opt_sse3;
bool opt_sse4;
bool opt_verbose;
static bool opt_A;
static bool opt_E;
static bool opt_M;
static bool opt_MD;
@ -56,6 +62,14 @@ static void usage(int status) {
exit(status);
}
static void version(void) {
printf("\
chibicc (cosmopolitan) 9.0.0\n\
copyright 2019 rui ueyama\n\
copyright 2020 justine alexandra roberts tunney\n");
exit(0);
}
static bool take_arg(char *arg) {
char *x[] = {"-o", "-I", "-idirafter", "-include",
"-x", "-MF", "-MT", "-Xlinker"};
@ -130,231 +144,171 @@ static void PrintMemoryUsage(void) {
fprintf(stderr, "allocated %,ld bytes of memory\n", mi.arena);
}
static void strarray_push_comma(StringArray *a, char *s) {
char *p;
for (; *s++ == ','; s = p) {
p = strchrnul(s, ',');
strarray_push(a, strndup(s, p - s));
}
}
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);
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")) {
} else if (!strcmp(argv[i], "-cc1")) {
opt_cc1 = true;
continue;
}
if (!strcmp(argv[i], "--help")) usage(0);
if (!strcmp(argv[i], "-v")) {
} else if (!strcmp(argv[i], "--help")) {
usage(0);
} else if (!strcmp(argv[i], "--version")) {
version();
} else if (!strcmp(argv[i], "-v")) {
opt_verbose = true;
atexit(PrintMemoryUsage);
continue;
}
if (!strcmp(argv[i], "-o")) {
} else if (!strcmp(argv[i], "-o")) {
opt_o = argv[++i];
continue;
}
if (!strncmp(argv[i], "-o", 2)) {
} else if (startswith(argv[i], "-o")) {
opt_o = argv[i] + 2;
continue;
}
if (!strcmp(argv[i], "-S")) {
} else 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")) {
} else if (!strcmp(argv[i], "-fcommon")) {
opt_common = true;
} else if (!strcmp(argv[i], "-fno-common")) {
opt_common = false;
} else if (!strcmp(argv[i], "-fno-builtin")) {
opt_no_builtin = true;
} else if (!strcmp(argv[i], "-c")) {
opt_c = true;
continue;
}
if (!strcmp(argv[i], "-E")) {
} else if (!strcmp(argv[i], "-E")) {
opt_E = true;
continue;
}
if (!strncmp(argv[i], "-I", 2)) {
} else if (!strcmp(argv[i], "-A")) {
opt_A = true;
} else if (!strcmp(argv[i], "-I")) {
strarray_push(&include_paths, argv[++i]);
} else if (startswith(argv[i], "-I")) {
strarray_push(&include_paths, argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-D")) {
} else if (!strcmp(argv[i], "-iquote")) {
strarray_push(&include_paths, argv[++i]);
} else if (startswith(argv[i], "-iquote")) {
strarray_push(&include_paths, argv[i] + strlen("-iquote"));
} else if (!strcmp(argv[i], "-isystem")) {
strarray_push(&include_paths, argv[++i]);
} else if (startswith(argv[i], "-isystem")) {
strarray_push(&include_paths, argv[i] + strlen("-isystem"));
} else if (!strcmp(argv[i], "-D")) {
define(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-D", 2)) {
} else if (startswith(argv[i], "-D")) {
define(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-U")) {
} else if (!strcmp(argv[i], "-U")) {
undef_macro(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-U", 2)) {
} else if (!strncmp(argv[i], "-U", 2)) {
undef_macro(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-include")) {
} else if (!strcmp(argv[i], "-include")) {
strarray_push(&opt_include, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-x")) {
} else if (!strcmp(argv[i], "-x")) {
opt_x = parse_opt_x(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-x", 2)) {
} else 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")) {
} else if (startswith(argv[i], "-Wa")) {
strarray_push_comma(&as_extra_args, argv[i]);
} else if (startswith(argv[i], "-Wl")) {
strarray_push_comma(&ld_extra_args, argv[i]);
} else if (!strcmp(argv[i], "-Xassembler")) {
strarray_push(&as_extra_args, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-Xlinker")) {
} else if (!strcmp(argv[i], "-Xlinker")) {
strarray_push(&ld_extra_args, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-s")) {
} else if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
strarray_push(&input_paths, argv[i]);
} else if (!strcmp(argv[i], "-s")) {
strarray_push(&ld_extra_args, "-s");
continue;
}
if (!strcmp(argv[i], "-M")) {
} else if (!strcmp(argv[i], "-M")) {
opt_M = true;
continue;
}
if (!strcmp(argv[i], "-MF")) {
} else if (!strcmp(argv[i], "-MF")) {
opt_MF = argv[++i];
continue;
}
if (!strcmp(argv[i], "-MP")) {
} else if (!strcmp(argv[i], "-MP")) {
opt_MP = true;
continue;
}
if (!strcmp(argv[i], "-MT")) {
if (opt_MT == NULL)
} else if (!strcmp(argv[i], "-MT")) {
if (!opt_MT) {
opt_MT = argv[++i];
else
} else {
opt_MT = xasprintf("%s %s", opt_MT, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-MD")) {
}
} else if (!strcmp(argv[i], "-MD")) {
opt_MD = true;
continue;
}
if (!strcmp(argv[i], "-MQ")) {
if (opt_MT == NULL)
} else if (!strcmp(argv[i], "-MQ")) {
if (!opt_MT) {
opt_MT = quote_makefile(argv[++i]);
else
} else {
opt_MT = xasprintf("%s %s", opt_MT, quote_makefile(argv[++i]));
continue;
}
if (!strcmp(argv[i], "-MMD")) {
}
} else if (!strcmp(argv[i], "-MMD")) {
opt_MD = opt_MMD = true;
continue;
}
if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") ||
!strcmp(argv[i], "-fPIC")) {
opt_fpic = true;
continue;
}
if (!strcmp(argv[i], "-pg")) {
} else if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") ||
!strcmp(argv[i], "-fPIC")) {
opt_pic = true;
} else 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")) {
} else if (!strcmp(argv[i], "-mfentry")) {
opt_fentry = true;
} else if (!strcmp(argv[i], "-ffunction-sections")) {
opt_function_sections = true;
} else if (!strcmp(argv[i], "-fdata-sections")) {
opt_data_sections = true;
} else if (!strcmp(argv[i], "-mrecord-mcount")) {
opt_record_mcount = true;
} else if (!strcmp(argv[i], "-mnop-mcount")) {
opt_nop_mcount = true;
} else if (!strcmp(argv[i], "-msse3")) {
opt_sse3 = true;
} else if (!strcmp(argv[i], "-msse4") || !strcmp(argv[i], "-msse4.2") ||
!strcmp(argv[i], "-msse4.1")) {
opt_sse4 = true;
} else if (!strcmp(argv[i], "-mpopcnt")) {
opt_popcnt = true;
} else if (!strcmp(argv[i], "-cc1-input")) {
base_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-cc1-output")) {
} else if (!strcmp(argv[i], "-cc1-output")) {
output_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-idirafter")) {
} else if (!strcmp(argv[i], "-idirafter")) {
strarray_push(&idirafter, argv[i++]);
continue;
}
if (!strcmp(argv[i], "-static")) {
} else if (!strcmp(argv[i], "-static")) {
opt_static = true;
strarray_push(&ld_extra_args, "-static");
continue;
}
if (!strcmp(argv[i], "-shared")) {
fprintf(stderr, "error: -shared not supported\n");
exit(1);
}
if (!strcmp(argv[i], "-L")) {
} else if (!strcmp(argv[i], "-shared")) {
error("-shared not supported");
} else 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)) {
} else if (startswith(argv[i], "-L")) {
strarray_push(&ld_extra_args, "-L");
strarray_push(&ld_extra_args, argv[i] + 2);
continue;
} else {
if (argv[i][0] == '-' && argv[i][1]) {
/* compiler should not whine about the flags race */
if (opt_verbose) {
fprintf(stderr, "unknown argument: %s\n", argv[i]);
}
} else {
strarray_push(&input_paths, argv[i]);
}
}
#if 0
if (!strcmp(argv[i], "-hashmap-test")) {
hashmap_test();
exit(0);
}
#endif
// These options are ignored for now.
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")) {
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++)
for (int i = 0; i < idirafter.len; i++) {
strarray_push(&include_paths, idirafter.data[i]);
if (input_paths.len == 0) error("no input files");
}
if (!input_paths.len) {
error("no input files");
}
// -E implies that the input is the C macro language.
if (opt_E) opt_x = FILE_C;
}
@ -439,13 +393,36 @@ static void run_cc1(int argc, char **argv, char *input, char *output) {
run_subprocess(args);
}
static void print_token(FILE *out, Token *tok) {
switch (tok->kind) {
case TK_STR:
switch (tok->ty->base->size) {
case 1:
fprintf(out, "%`'.*s", tok->ty->array_len - 1, tok->str);
break;
case 2:
fprintf(out, "%`'.*hs", tok->ty->array_len - 1, tok->str);
break;
case 4:
fprintf(out, "%`'.*ls", tok->ty->array_len - 1, tok->str);
break;
default:
UNREACHABLE();
}
break;
default:
fprintf(out, "%.*s", tok->len, tok->loc);
break;
}
}
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");
if (tok->has_space && !tok->at_bol) fprintf(out, " ");
fprintf(out, "%.*s", tok->len, tok->loc);
print_token(out, tok);
line++;
}
fprintf(out, "\n");
@ -547,7 +524,10 @@ static void cc1(void) {
return;
}
Obj *prog = parse(tok);
// Traverse the AST to emit assembly.
if (opt_A) {
print_ast(stdout, prog);
return;
}
FILE *out = open_file(output_file);
codegen(prog, out);
fclose(out);
@ -582,7 +562,7 @@ static void run_linker(StringArray *inputs, char *output) {
strarray_push(&arr, "elf_x86_64");
strarray_push(&arr, "-z");
strarray_push(&arr, "max-page-size=0x1000");
strarray_push(&arr, "-mnostdlib");
strarray_push(&arr, "-nostdlib");
strarray_push(&arr, "--gc-sections");
strarray_push(&arr, "--build-id=none");
strarray_push(&arr, "--no-dynamic-linker");
@ -611,8 +591,9 @@ int main(int argc, char **argv) {
cc1();
return 0;
}
if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))
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];
@ -650,7 +631,7 @@ int main(int argc, char **argv) {
}
continue;
}
assert(type == FILE_C);
assert(type == FILE_C || type == FILE_ASM_CPP);
// Just preprocess
if (opt_E || opt_M) {
run_cc1(argc, argv, input, NULL);

View File

@ -114,7 +114,7 @@ void warn_tok(Token *, char *, ...)
File **get_input_files(void);
File *new_file(char *, int, char *);
Token *skip(Token *, char *);
Token *skip(Token *, char);
Token *tokenize(File *);
Token *tokenize_file(char *);
Token *tokenize_string_literal(Token *, Type *);
@ -269,10 +269,10 @@ typedef enum {
ND_MUL, // *
ND_DIV, // /
ND_NEG, // unary -
ND_MOD, // %
ND_BITAND, // &
ND_BITOR, // |
ND_BITXOR, // ^
ND_REM, // %
ND_BINAND, // &
ND_BINOR, // |
ND_BINXOR, // ^
ND_SHL, // <<
ND_SHR, // >>
ND_EQ, // ==
@ -329,61 +329,44 @@ struct Node {
Node *inc;
// Block or statement expression
Node *body;
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;
};
};
// Function call
Type *func_ty;
Node *args;
Obj *ret_buffer;
bool pass_by_stack;
bool realign_stack;
// 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 member access
Member *member;
// Assembly
Asm *azm;
// 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;
// Arithmetic
Node *overflow;
// Numeric literal
int64_t val;
long double fval;
FpClassify *fpc;
};
Node *expr(Token **, Token *);
@ -396,6 +379,12 @@ int64_t const_expr(Token **, Token *);
int64_t eval(Node *);
int64_t eval2(Node *, char ***);
//
// debug.c
//
void print_ast(FILE *, Obj *);
//
// type.c
//
@ -560,15 +549,20 @@ void hashmap_test(void);
//
extern StringArray include_paths;
extern bool opt_fcommon;
extern bool opt_fpic;
extern bool opt_verbose;
extern bool opt_mpopcnt;
extern char *base_file;
extern bool opt_common;
extern bool opt_data_sections;
extern bool opt_fentry;
extern bool opt_function_sections;
extern bool opt_no_builtin;
extern bool opt_nop_mcount;
extern bool opt_pg;
extern bool opt_mfentry;
extern bool opt_mnop_mcount;
extern bool opt_mrecord_mcount;
extern bool opt_pic;
extern bool opt_popcnt;
extern bool opt_record_mcount;
extern bool opt_sse3;
extern bool opt_sse4;
extern bool opt_verbose;
extern char *base_file;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -55,6 +55,7 @@ THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
LIBC_TIME \
LIBC_UNICODE \
LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA
@ -73,10 +74,10 @@ $(THIRD_PARTY_CHIBICC_A).pkg: \
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 \
$(APE) \
$(CRT) \
$(APE)
o/$(MODE)/third_party/chibicc/chibicc.o \
$(THIRD_PARTY_CHIBICC_A).pkg
@$(APELINK)
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
@ -93,16 +94,16 @@ o/$(MODE)/third_party/chibicc/chibicc.o: \
-DAPE=\"o/$(MODE)/ape/ape.o\" \
-DLDS=\"o/$(MODE)/ape/ape.lds\"
o/$(MODE)/third_party/chibicc/chibicc.chibicc.s: \
o/$(MODE)/third_party/chibicc/chibicc.chibicc.o: \
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 $@ $<
o/$(MODE)/%.chibicc.o: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg
@ACTION=CHIBICC TARGET=$@ build/do $(CHIBICC) $(CHIBICC_FLAGS) -c -o $@ $<
o/$(MODE)/%.chibicc2.o: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
@ACTION=CHIBICC2 TARGET=$@ build/do $(CHIBICC2) $(CHIBICC_FLAGS) -c -o $@ $<
THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)))
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
@ -115,5 +116,4 @@ $(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk
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)
$(THIRD_PARTY_CHIBICC_CHECKS)

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,11 @@ static uint64_t fnv_hash(char *s, int len) {
static void rehash(HashMap *map) {
// Compute the size of the new hashmap.
int nkeys = 0;
for (int i = 0; i < map->capacity; i++)
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++;
for (int i = 0; i < map->capacity; i++) {
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) {
nkeys++;
}
}
size_t cap = map->capacity;
while ((nkeys * 100) / cap >= 50) cap = cap * 2;
// Create a new hashmap and copy all key-values.
@ -101,32 +104,3 @@ void hashmap_delete2(HashMap *map, char *key, int keylen) {
HashEntry *ent = get_entry(map, key, 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, 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, xasprintf("key %d", i), (void *)(size_t)i);
for (int i = 6000; i < 7000; 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, 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, 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, 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, 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

@ -253,7 +253,7 @@ static Token *read_const_expr(Token **rest, Token *tok) {
error_tok(start, "macro name must be an identifier");
Macro *m = find_macro(tok);
tok = tok->next;
if (has_paren) tok = skip(tok, ")");
if (has_paren) tok = skip(tok, ')');
cur = cur->next = new_num_token(m ? 1 : 0, start);
continue;
}
@ -318,16 +318,16 @@ static MacroParam *read_macro_params(Token **rest, Token *tok,
MacroParam head = {};
MacroParam *cur = &head;
while (!EQUAL(tok, ")")) {
if (cur != &head) tok = skip(tok, ",");
if (cur != &head) tok = skip(tok, ',');
if (EQUAL(tok, "...")) {
*va_args_name = "__VA_ARGS__";
*rest = skip(tok->next, ")");
*rest = skip(tok->next, ')');
return head.next;
}
if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier");
if (EQUAL(tok->next, "...")) {
*va_args_name = strndup(tok->loc, tok->len);
*rest = skip(tok->next->next, ")");
*rest = skip(tok->next->next, ')');
return head.next;
}
MacroParam *m = calloc(1, sizeof(MacroParam));
@ -386,7 +386,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params,
MacroArg *cur = &head;
MacroParam *pp = params;
for (; pp; pp = pp->next) {
if (cur != &head) tok = skip(tok, ",");
if (cur != &head) tok = skip(tok, ',');
cur = cur->next = read_macro_arg_one(&tok, tok, false);
cur->name = pp->name;
}
@ -396,25 +396,27 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params,
arg = calloc(1, sizeof(MacroArg));
arg->tok = new_eof(tok);
} else {
if (pp != params) tok = skip(tok, ",");
if (pp != params) tok = skip(tok, ',');
arg = read_macro_arg_one(&tok, tok, true);
}
arg->name = va_args_name;
;
arg->is_va_args = true;
cur = cur->next = arg;
} else if (pp) {
error_tok(start, "too many arguments");
}
skip(tok, ")");
skip(tok, ')');
*rest = tok;
return head.next;
}
static MacroArg *find_arg(MacroArg *args, Token *tok) {
for (MacroArg *ap = args; ap; ap = ap->next)
if (tok->len == strlen(ap->name) && !strncmp(tok->loc, ap->name, tok->len))
for (MacroArg *ap = args; ap; ap = ap->next) {
if (tok->len == strlen(ap->name) &&
!strncmp(tok->loc, ap->name, tok->len)) {
return ap;
}
}
return NULL;
}
@ -543,7 +545,7 @@ static Token *subst(Token *tok, MacroArg *args) {
if (has_varargs(args))
for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
cur = cur->next = t;
tok = skip(tok, ")");
tok = skip(tok, ')');
continue;
}
// Handle a macro token. Macro arguments are completely macro-expanded
@ -932,11 +934,11 @@ __chibicc__\000\
__cosmopolitan__\000\
1\000\
__GNUC__\000\
6\000\
9\000\
__GNUC_MINOR__\000\
6\000\
0\000\
__GNUC_PATCHLEVEL__\000\
6\000\
0\000\
__NO_INLINE__\000\
16\000\
__BIGGEST_ALIGNMENT__\000\
@ -1289,9 +1291,13 @@ static void join_adjacent_string_literals(Token *tok) {
"unsupported non-standard concatenation of string literals");
}
}
if (basety->size > 1)
for (Token *t = tok1; t->kind == TK_STR; t = t->next)
if (t->ty->base->size == 1) *t = *tokenize_string_literal(t, basety);
if (basety->size > 1) {
for (Token *t = tok1; t->kind == TK_STR; t = t->next) {
if (t->ty->base->size == 1) {
*t = *tokenize_string_literal(t, basety);
}
}
}
while (tok1->kind == TK_STR) tok1 = tok1->next;
}
// Second pass: concatenate adjacent string literals.
@ -1307,10 +1313,9 @@ static void join_adjacent_string_literals(Token *tok) {
array_of(tok1->ty->base, tok1->ty->array_len + tok2->ty->array_len - 1);
t->str = calloc(1, t->ty->size);
t->next = tok2->next;
int i = 0;
for (int j = 0; j < tok1->ty->size - tok1->ty->base->size; i++, j++)
t->str[i] = tok1->str[j];
for (int j = 0; j < tok2->ty->size; i++, j++) t->str[i] = tok2->str[j];
memcpy(mempcpy(t->str, tok1->str, tok1->ty->size - tok1->ty->base->size),
tok2->str, tok2->ty->size);
t->len = strlen(t->loc);
*tok1 = *t;
}
}

249
third_party/chibicc/printast.c vendored Normal file
View File

@ -0,0 +1,249 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/arraylist2.internal.h"
#include "third_party/chibicc/chibicc.h"
static const char kBoolStr[2][6] = {"false", "true"};
static const char kTypeKindStr[17][8] = {
"VOID", "BOOL", "CHAR", "SHORT", "INT", "LONG",
"INT128", "FLOAT", "DOUBLE", "LDOUBLE", "ENUM", "PTR",
"FUNC", "ARRAY", "VLA", "STRUCT", "UNION",
};
static const char kNodeKindStr[50][11] = {
"NULL_EXPR", "ADD", "SUB", "MUL", "DIV", "NEG",
"REM", "BINAND", "BINOR", "BINXOR", "SHL", "SHR",
"EQ", "NE", "LT", "LE", "ASSIGN", "COND",
"COMMA", "MEMBER", "ADDR", "DEREF", "NOT", "BITNOT",
"LOGAND", "LOGOR", "RETURN", "IF", "FOR", "DO",
"SWITCH", "CASE", "BLOCK", "GOTO", "GOTO_EXPR", "LABEL",
"LABEL_VAL", "FUNCALL", "EXPR_STMT", "STMT_EXPR", "VAR", "VLA_PTR",
"NUM", "CAST", "MEMZERO", "ASM", "CAS", "EXCH",
"FPCLASSIFY",
};
static struct Visited {
size_t i, n;
intptr_t *p;
} g_visited;
static void PrintObj(FILE *, int, const char *, Obj *);
static void PrintNode(FILE *, int, const char *, Node *);
static void PrintType(FILE *, int, const char *, Type *);
static bool Visit(void *ptr) {
size_t i;
intptr_t addr = (intptr_t)ptr;
for (i = 0; i < g_visited.i; ++i) {
if (addr == g_visited.p[i]) {
return false;
}
}
APPEND(&g_visited.p, &g_visited.i, &g_visited.n, &addr);
return true;
}
static void PrintLine(FILE *f, int l, char *fmt, ...) {
int i;
va_list ap;
for (i = 0; i < l; ++i) fputc(' ', f);
va_start(ap, fmt);
vfprintf(f, fmt, ap);
va_end(ap);
fputc('\n', f);
}
static void PrintBool(FILE *f, int l, const char *s, bool b) {
if (!b) return;
PrintLine(f, l, "%s%s", s, kBoolStr[b]);
}
static void PrintInt(FILE *f, int l, const char *s, long x) {
if (!x) return;
PrintLine(f, l, "%s%ld", s, x);
}
static void PrintStr(FILE *f, int l, const char *s, const char *t) {
if (!t || !*t) return;
PrintLine(f, l, "%s%`'s", s, t);
}
static void PrintTokStr(FILE *f, int l, const char *s, Token *t) {
if (!t) return;
PrintLine(f, l, "%s%`'.*s", s, t->len, t->loc);
}
static void PrintMember(FILE *f, int l, const char *s, Member *m) {
if (!m) return;
PrintLine(f, l, "%sMember { # %p", s, m);
PrintTokStr(f, l + 2, "name: ", m->name);
PrintInt(f, l + 2, "idx: ", m->idx);
PrintInt(f, l + 2, "align: ", m->align);
PrintInt(f, l + 2, "offset: ", m->offset);
PrintBool(f, l + 2, "is_bitfield: ", m->is_bitfield);
PrintInt(f, l + 2, "bit_offset: ", m->bit_offset);
PrintInt(f, l + 2, "bit_width: ", m->bit_width);
PrintType(f, l + 2, "ty: ", m->ty);
PrintLine(f, l, "}");
}
static void PrintMembers(FILE *f, int l, const char *s, Member *m) {
for (; m; m = m->next) {
PrintMember(f, l, s, m);
}
}
static void PrintType(FILE *f, int l, const char *s, Type *t) {
for (; t; t = t->next) {
if (Visit(t)) {
PrintLine(f, l, "%sType { # %p", s, t);
PrintLine(f, l + 2, "kind: TY_%s", kTypeKindStr[t->kind]);
PrintInt(f, l + 2, "size: ", t->size);
PrintInt(f, l + 2, "align: ", t->align);
PrintBool(f, l + 2, "is_unsigned: ", t->is_unsigned);
PrintBool(f, l + 2, "is_atomic: ", t->is_atomic);
PrintType(f, l + 2, "origin: ", t->origin);
PrintType(f, l + 2, "base: ", t->base);
PrintTokStr(f, l + 2, "name: ", t->name);
PrintTokStr(f, l + 2, "name_pos: ", t->name_pos);
PrintInt(f, l + 2, "array_len: ", t->array_len);
PrintInt(f, l + 2, "vector_size: ", t->vector_size);
PrintNode(f, l + 2, "vla_len: ", t->vla_len);
PrintObj(f, l + 2, "vla_size: ", t->vla_size);
PrintMembers(f, l + 2, "members: ", t->members);
PrintBool(f, l + 2, "is_flexible: ", t->is_flexible);
PrintBool(f, l + 2, "is_packed: ", t->is_packed);
PrintBool(f, l + 2, "is_aligned: ", t->is_aligned);
PrintType(f, l + 2, "return_ty: ", t->return_ty);
PrintType(f, l + 2, "params: ", t->params);
PrintBool(f, l + 2, "is_variadic: ", t->is_variadic);
PrintLine(f, l, "}");
} else if (t->name) {
PrintLine(f, l, "%sTY_%s %.*s # %p", s, kTypeKindStr[t->kind],
t->name->len, t->name->loc, t);
} else {
PrintLine(f, l, "%sTY_%s # %p", s, kTypeKindStr[t->kind], t);
}
}
}
static void PrintAsm(FILE *f, int l, const char *s, Asm *a) {
int i;
if (!a) return;
PrintLine(f, l, "%sAsm { # %p", s, a);
PrintStr(f, l + 2, "str: ", a->str);
for (i = 0; i < a->n; ++i) {
PrintLine(f, l + 2, "ops: AsmOperand {");
PrintStr(f, l + 4, "str: ", a->ops[i].str);
PrintNode(f, l + 4, "node: ", a->ops[i].node);
PrintLine(f, l + 2, "}");
}
PrintLine(f, l, "}");
}
static void PrintNode(FILE *f, int l, const char *s, Node *n) {
for (; n; n = n->next) {
PrintLine(f, l, "%sNode { # %p", s, n);
PrintLine(f, l + 2, "kind: ND_%s", kNodeKindStr[n->kind]);
PrintType(f, l + 2, "ty: ", n->ty);
PrintNode(f, l + 2, "lhs: ", n->lhs);
PrintNode(f, l + 2, "rhs: ", n->rhs);
PrintNode(f, l + 2, "cond: ", n->cond);
PrintNode(f, l + 2, "then: ", n->then);
PrintNode(f, l + 2, "els: ", n->els);
PrintNode(f, l + 2, "init: ", n->init);
PrintNode(f, l + 2, "inc: ", n->inc);
PrintNode(f, l + 2, "body: ", n->body);
PrintType(f, l + 2, "func_ty: ", n->func_ty);
PrintNode(f, l + 2, "args: ", n->args);
PrintObj(f, l + 2, "ret_buffer: ", n->ret_buffer);
PrintBool(f, l + 2, "pass_by_stack: ", n->pass_by_stack);
PrintBool(f, l + 2, "realign_stack: ", n->realign_stack);
PrintNode(f, l + 2, "case_next: ", n->case_next);
PrintNode(f, l + 2, "default_case: ", n->default_case);
PrintStr(f, l + 2, "label: ", n->label);
PrintStr(f, l + 2, "unique_label: ", n->unique_label);
PrintNode(f, l + 2, "goto_next: ", n->goto_next);
PrintStr(f, l + 2, "brk_label: ", n->brk_label);
PrintStr(f, l + 2, "cont_label: ", n->cont_label);
PrintInt(f, l + 2, "begin: ", n->begin);
PrintAsm(f, l + 2, "azm: ", n->azm);
PrintInt(f, l + 2, "end: ", n->end);
PrintMember(f, l + 2, "member: ", n->member);
PrintObj(f, l + 2, "var: ", n->var);
PrintNode(f, l + 2, "overflow: ", n->overflow);
PrintInt(f, l + 2, "val: ", n->val);
if (n->fval) PrintLine(f, l + 2, "fval: %Lf", n->fval);
PrintLine(f, l, "}");
}
}
static void PrintRelo(FILE *f, int l, const char *s, Relocation *r) {
for (; r; r = r->next) {
PrintLine(f, l, "%sRelocation { # %p", s, r);
PrintInt(f, l + 2, "offset: ", r->offset);
if (r->label) PrintStr(f, l + 2, "label: ", *r->label);
PrintInt(f, l + 2, "addend: ", r->addend);
PrintLine(f, l, "}");
}
}
static void PrintObj(FILE *f, int l, const char *s, Obj *o) {
if (!o) return;
PrintLine(f, l, "%sObj { # %p", s, o);
PrintStr(f, l + 2, "name: ", o->name);
PrintType(f, l + 2, "ty: ", o->ty);
PrintBool(f, l + 2, "is_local: ", o->is_local);
PrintInt(f, l + 2, "align: ", o->align);
PrintInt(f, l + 2, "offset: ", o->offset);
PrintBool(f, l + 2, "is_function: ", o->is_function);
PrintBool(f, l + 2, "is_definition: ", o->is_definition);
PrintBool(f, l + 2, "is_static: ", o->is_static);
PrintBool(f, l + 2, "is_weak: ", o->is_weak);
PrintBool(f, l + 2, "is_externally_visible: ", o->is_externally_visible);
PrintStr(f, l + 2, "asmname: ", o->asmname);
PrintStr(f, l + 2, "section: ", o->section);
PrintStr(f, l + 2, "visibility: ", o->visibility);
PrintBool(f, l + 2, "is_tentative: ", o->is_tentative);
PrintBool(f, l + 2, "is_string_literal: ", o->is_string_literal);
PrintBool(f, l + 2, "is_tls: ", o->is_tls);
PrintStr(f, l + 2, "init_data: ", o->init_data);
PrintRelo(f, l + 2, "rel: ", o->rel);
PrintBool(f, l + 2, "is_inline: ", o->is_inline);
PrintBool(f, l + 2, "is_aligned: ", o->is_aligned);
PrintBool(f, l + 2, "is_noreturn: ", o->is_noreturn);
PrintBool(f, l + 2, "is_destructor: ", o->is_destructor);
PrintBool(f, l + 2, "is_constructor: ", o->is_constructor);
PrintInt(f, l + 2, "stack_size: ", o->stack_size);
PrintObj(f, l + 2, "params: ", o->params);
PrintNode(f, l + 2, "body: ", o->body);
PrintObj(f, l + 2, "locals: ", o->locals);
PrintObj(f, l + 2, "va_area: ", o->va_area);
PrintObj(f, l + 2, "alloca_bottom: ", o->alloca_bottom);
PrintBool(f, l + 2, "is_live: ", o->is_live);
PrintBool(f, l + 2, "is_root: ", o->is_root);
PrintLine(f, l, "}");
}
void print_ast(FILE *f, Obj *o) {
for (; o; o = o->next) {
PrintObj(f, 0, "", o);
}
}

View File

@ -11,7 +11,7 @@ int main() {
char *p2 = alloca(16);
char *p3 = 1 + (char *)alloca(3) + 1;
p3 -= 2;
char *p4 = fn(1, alloca(16), 3);
char *p4 = fn(1, __builtin_alloca(16), 3);
ASSERT(16, p1 - p2);
ASSERT(16, p2 - p3);

View File

@ -128,5 +128,11 @@ int main() {
ASSERT(9, v1[6]);
ASSERT(10, v1[7]);
{
char *p;
asm("mov\t%1,%0" : "=r"(p) : "r"("hello"));
ASSERT(1, !strcmp(p, "hello"));
}
return 0;
}

View File

@ -0,0 +1,8 @@
#include "third_party/chibicc/test/test.h"
_Static_assert(1);
_Static_assert(1, "hey");
main() {
_Static_assert(sizeof(int) == 4, "wut");
}

View File

@ -1,6 +1,21 @@
#include "third_party/chibicc/test/test.h"
void doge() __attribute__((__nonnull__));
void cate(char *) __attribute__((__nonnull__(1)));
int var __attribute__((__section__(".data.var")));
int ar[4] __attribute__((__section__(".data.var")));
typedef int int2[2] __attribute__((__aligned__(64)));
typedef int int4[4] __attribute__((__warn_if_not_aligned__(16)));
__attribute__((__nonnull__)) void doge2();
__attribute__((__nonnull__(1))) void cate2(char *);
__attribute__((__section__(".data.var"))) int var2;
__attribute__((__section__(".data.var"))) int ar2[4];
int main() {
int2 a;
ASSERT(64, _Alignof(int2));
ASSERT(64, _Alignof(a));
ASSERT(5, ({
struct {
char a;

View File

@ -8,10 +8,87 @@
#define FPCLASSIFY(x) \
__builtin_fpclassify(FPNAN, FPINFINITE, FPNORMAL, FPSUBNORMAL, FPZERO, x)
#define conceal(x) \
({ \
typeof(x) cloak = x; \
asm("" : "+r"(cloak)); \
cloak; \
})
struct frame {
struct frame *next;
intptr_t addr;
};
struct frame *frame(void) {
struct frame *myframe = __builtin_frame_address(0);
struct frame *parentframe = myframe->next;
return parentframe;
}
void test_frame_address(void) {
ASSERT(1, __builtin_frame_address(0) == frame());
}
void test_constant(void) {
ASSERT(1, __builtin_constant_p(1));
ASSERT(0, __builtin_constant_p(conceal(1)));
ASSERT(0, __builtin_constant_p(stdin));
ASSERT(1, __builtin_constant_p(__builtin_popcount(0b10111011)));
ASSERT(1, __builtin_constant_p(__builtin_popcountll((size_t)0b10111011)));
}
void test_ignored(void) {
ASSERT(123, __builtin_assume_aligned(123, 8));
ASSERT(123, __builtin_assume_aligned(123, 32, 8));
ASSERT(123, __builtin_expect(123, 0));
}
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));
ASSERT(25, __builtin_clz(conceal(77)));
__builtin_clz(conceal(77));
}
__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));
ASSERT(0, __builtin_ctz(conceal(77)));
}
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));
ASSERT(1, __builtin_ffs(conceal(77)));
}
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));
ASSERT(6, __builtin_popcountl(conceal(0b10111011)));
}
void test_bswap(void) {
ASSERT(0x3412, __builtin_bswap16(0x1234));
ASSERT(0x78563412, __builtin_bswap32(0x12345678));
ASSERT(0xefcdab8967452301, __builtin_bswap64(0x0123456789abcdef));
ASSERT(0xefcdab89, __builtin_bswap32(0x0123456789abcdef));
ASSERT(0x78563412, __builtin_bswap32(conceal(0x12345678)));
}
void test_fpclassify(void) {
@ -38,48 +115,34 @@ void test_fpclassify(void) {
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));
void test_strlen(void) {
ASSERT(5, strlen("hello"));
ASSERT(5, __builtin_strlen("hello"));
}
__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_strchr(void) {
ASSERT(1, __builtin_strchr("hello", 'z') == NULL);
ASSERT(0, (strcmp)(__builtin_strchr("hello", 'e'), "ello"));
}
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_strpbrk(void) {
ASSERT(1, __builtin_strpbrk("hello", "z") == NULL);
ASSERT(0, (strcmp)(__builtin_strpbrk("hello", "ze"), "ello"));
}
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_strstr(void) {
ASSERT(1, __builtin_strstr("hello", "sup") == NULL);
ASSERT(0, (strcmp)(__builtin_strstr("hello", "ell"), "ello"));
}
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 == (memcpy)(x, y + 2, 3));
ASSERT(0, memcmp(x, z, 5));
}
{
char x[5] = {4, 3, 2, 1, 0};
char y[5] = {0, 1, 2, 3, 4};
@ -95,6 +158,109 @@ void test_memcpy(void) {
ASSERT(1, x == __builtin_memcpy(x, y + 2, n));
ASSERT(0, memcmp(x, z, 5));
}
{
char x[5] = {4, 3, 2, 1, 0};
ASSERT(1, x == __builtin_memcpy(x, x + 1, 4));
ASSERT(0, memcmp(x, (char[5]){3, 2, 1, 0, 0}, 5));
}
}
void test_add_overflow(void) {
{
int z;
ASSERT(0, __builtin_add_overflow(2, 3, &z));
ASSERT(5, z);
}
{
int x, y, z;
x = 2;
y = 3;
ASSERT(0, __builtin_add_overflow(x, y, &z));
ASSERT(5, z);
}
{
int x, y, z;
x = 0x7fffffff;
y = 1;
ASSERT(1, __builtin_add_overflow(x, y, &z));
ASSERT(-2147483648, z);
}
{
long x, y, z;
x = 0x7fffffff;
y = 1;
ASSERT(0, __builtin_add_overflow(x, y, &z));
ASSERT(2147483648, z);
}
}
void test_sub_overflow(void) {
{
int x, y, z;
x = 2;
y = 3;
ASSERT(0, __builtin_sub_overflow(x, y, &z));
ASSERT(-1, z);
}
{
int x, y, z;
x = -2147483648;
y = 1;
ASSERT(1, __builtin_sub_overflow(x, y, &z));
ASSERT(2147483647, z);
}
{
long x, y, z;
x = -2147483648;
y = 1;
ASSERT(0, __builtin_sub_overflow(x, y, &z));
ASSERT(-2147483649, z);
}
}
void test_mul_overflow(void) {
{
int x, y, z;
x = 2;
y = 3;
ASSERT(0, __builtin_mul_overflow(x, y, &z));
ASSERT(6, z);
}
{
int x, y, z;
x = 2147483647;
y = 2;
ASSERT(1, __builtin_mul_overflow(x, y, &z));
ASSERT(-2, z);
}
{
long x, y, z;
x = 2147483647;
y = 2;
ASSERT(0, __builtin_mul_overflow(x, y, &z));
ASSERT(4294967294, z);
}
}
void test_neg_overflow(void) {
{
int x, z;
x = 2;
ASSERT(0, __builtin_neg_overflow(x, &z));
ASSERT(-2, z);
}
{
int x, z;
x = -2147483648;
ASSERT(1, __builtin_neg_overflow(x, &z));
ASSERT(-2147483648, z);
}
{
long x, z;
x = -2147483648;
ASSERT(0, __builtin_neg_overflow(x, &z));
ASSERT(2147483648, z);
}
}
void test_inf(void) {
@ -225,6 +391,7 @@ void test_offsetof(void) {
int main() {
test_constant();
test_frame_address();
test_types_compatible_p();
test_clz();
test_ctz();
@ -238,5 +405,14 @@ int main() {
test_signbit();
test_memcpy();
test_offsetof();
test_ignored();
test_add_overflow();
test_sub_overflow();
test_mul_overflow();
test_neg_overflow();
test_strlen();
test_strchr();
test_strpbrk();
test_strstr();
return 0;
}

View File

@ -176,6 +176,4 @@ int main() {
ASSERT(1, g40 == 1.5);
ASSERT(1, g41 == 11);
return 0;
}

42
third_party/chibicc/test/dce_test.c vendored Normal file
View File

@ -0,0 +1,42 @@
#include "third_party/chibicc/test/test.h"
int x;
int main(void) {
if (0) {
asm(".error \"the assembler shall fail\"");
}
x = 1 ? 777 : ({
asm(".error \"the system is down\"");
666;
});
ASSERT(777, x);
x = 0;
x = 777 ?: ({
asm(".error \"the system is down\"");
666;
});
x = 0;
x = __builtin_popcount(strlen("hihi")) == 1 ? 777 : ({
asm(".error \"the system is down\"");
666;
});
ASSERT(777, x);
x = 0;
x = strpbrk("hihi", "ei") ? 777 : ({
asm(".error \"the system is down!\"");
666;
});
ASSERT(777, x);
x = 0;
x = !__builtin_strpbrk("HELLO\n", "bxdinupo") ? 777 : ({
asm(".error \"the system is down\"");
666;
});
ASSERT(777, x);
}

View File

@ -87,26 +87,8 @@ 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);
}
int add_all(int, ...);
int add_all(int, ...);
double add_double(double x, double y);
float add_float(float x, float y);
@ -307,7 +289,7 @@ int main() {
{
char buf[100];
fmt(buf, "%d %d %s", 1, 2, "foo");
sprintf(buf, "%d %d %s", 1, 2, "foo");
fprintf(f, "%s\n", buf);
}
@ -319,7 +301,7 @@ int main() {
ASSERT(0, ({
char buf[100];
fmt(buf, "%d %d %s", 1, 2, "foo");
sprintf(buf, "%d %d %s", 1, 2, "foo");
strcmp("1 2 foo", buf);
}));
@ -342,7 +324,7 @@ int main() {
ASSERT(0, ({
char buf[100];
fmt(buf, "%.1f", (float)3.5);
sprintf(buf, "%.1f", (float)3.5);
strcmp(buf, "3.5");
}));

4
third_party/chibicc/test/hog_test.c vendored Normal file
View File

@ -0,0 +1,4 @@
main(void) {
void *p;
p = "hello";
}

View File

@ -33,7 +33,17 @@ __int128 sub128x5(__int128 a, __int128 b, __int128 c, __int128 d, __int128 e) {
return a - b - c - d - e;
}
__int128 sub128x6(int f, __int128 a, __int128 b, __int128 c, __int128 d,
__int128 e) {
return f - a - b - c - d - e;
}
void lotsOfArgs(const char *file, int line, const char *func, intmax_t beg,
intmax_t end, intmax_t got, const char *gotcode, bool isfatal) {
}
void testLang128(void) {
lotsOfArgs(__FILE__, __LINE__, __FUNCTION__, 0, 0, 0, "", false);
ASSERT(16, sizeof(__int128));
ASSERT(16, sizeof(unsigned __int128));
ASSERT(16, _Alignof(__int128));
@ -64,6 +74,12 @@ void testLang128(void) {
I128(0x19a0da005190a5ac, 0x755fa06484419e38),
I128(0xafc6e44400b9eadd, 0x05e5afdb2e66cdb8),
I128(0x5380c8796909a165, 0x47657977e6c4f381)));
ASSERT128(I128(0x1f1b109234418f84, 0x21f9f24c8535e4f0),
sub128x6(0x5ab6ba38, I128(0x0db9cd085ab6ba38, 0xdaf9c05f15896b5f),
I128(0xb6429ba7b5b38454, 0x4061839d268a0a78),
I128(0x19a0da005190a5ac, 0x755fa06484419e38),
I128(0xafc6e44400b9eadd, 0x05e5afdb2e66cdb8),
I128(0x5380c8796909a165, 0x47657977e6c4f381)));
}
void testCompare128(void) {
@ -8157,6 +8173,27 @@ void testNot128(void) {
ASSERT128(I128(0, 0), ~x);
}
void testAbi(void) {
ASSERT(0, ({
char buf[200];
sprintf(buf, "%d %d %d %d %032jx %032jx", 1, 2, 3, 4,
I128(0x1ffffffff, 0x2ffffffff),
I128(0x3eeeeeeee, 0x4eeeeeeee));
strcmp("1 2 3 4 00000001ffffffff00000002ffffffff "
"00000003eeeeeeee00000004eeeeeeee",
buf);
}));
ASSERT(0, ({
char buf[200];
sprintf(buf, "%d %d %d %d %d %032jx %032jx", 1, 2, 3, 4, 5,
I128(0x1ffffffff, 0x2ffffffff),
I128(0x3eeeeeeee, 0x4eeeeeeee));
strcmp("1 2 3 4 5 00000001ffffffff00000002ffffffff "
"00000003eeeeeeee00000004eeeeeeee",
buf);
}));
}
int main(void) {
testLang128();
testCompare128();
@ -8179,5 +8216,6 @@ int main(void) {
testCastDblUint128();
testCastLdblInt128();
testCastLdblUint128();
testAbi();
return 0;
}

View File

@ -1,6 +1,9 @@
#include "third_party/chibicc/test/test.h"
int main() {
typeof("str") StringInitParen1 = ("str");
char StringInitParen2[] = ("str");
ASSERT(0, ""[0]);
ASSERT(1, sizeof(""));

View File

@ -49,6 +49,8 @@ THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_UNICODE \
LIBC_MEM \
LIBC_X \
THIRD_PARTY_CHIBICC \
THIRD_PARTY_COMPILER_RT
THIRD_PARTY_CHIBICC_TEST_DEPS := \
@ -95,6 +97,4 @@ o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
.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)
$(THIRD_PARTY_CHIBICC_TEST_CHECKS)

View File

@ -24,6 +24,12 @@ int main() {
sizeof(x);
}));
ASSERT(12, sizeof(typeof(struct { int a, b, c; })));
return 0;
ASSERT(3, ({
label:
3;
}));
ASSERT(3, ({
__typeof(int) x = 3;
x;
}));
}

View File

@ -1,6 +1,6 @@
#include "third_party/chibicc/chibicc.h"
#define LOOKINGAT(TOK, OP) lookingat(TOK, OP, strlen(OP))
#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, strlen(OP)))
// Input file
static File *current_file;
@ -75,29 +75,18 @@ 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, size_t n) {
return n == tok->len && !compare_strings(tok->loc, op, tok->len);
return n == tok->len && !memcmp(tok->loc, op, tok->len);
}
bool consume(Token **rest, Token *tok, char *str, size_t n) {
if (n == tok->len && !compare_strings(tok->loc, str, n)) {
if (n == tok->len && !memcmp(tok->loc, str, n)) {
*rest = tok->next;
return true;
}
@ -106,9 +95,12 @@ bool consume(Token **rest, Token *tok, char *str, size_t n) {
}
// 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;
Token *skip(Token *tok, char op) {
if (tok->len == 1 && *tok->loc == op) {
return tok->next;
} else {
error_tok(tok, "expected '%c'", op);
}
}
// Create a new token and add it as the next token of `cur`.

View File

@ -166,10 +166,10 @@ void add_type(Node *node) {
case ND_SUB:
case ND_MUL:
case ND_DIV:
case ND_MOD:
case ND_BITAND:
case ND_BITOR:
case ND_BITXOR:
case ND_REM:
case ND_BINAND:
case ND_BINOR:
case ND_BINXOR:
usual_arith_conv(&node->lhs, &node->rhs);
node->ty = node->lhs->ty;
return;
@ -226,10 +226,11 @@ void add_type(Node *node) {
return;
case ND_ADDR: {
Type *ty = node->lhs->ty;
if (ty->kind == TY_ARRAY)
if (ty->kind == TY_ARRAY) {
node->ty = pointer_to(ty->base);
else
} else {
node->ty = pointer_to(ty);
}
return;
}
case ND_DEREF:
@ -251,7 +252,17 @@ void add_type(Node *node) {
case ND_STMT_EXPR:
if (node->body) {
Node *stmt = node->body;
while (stmt->next) stmt = stmt->next;
for (;;) {
if (stmt->next) {
stmt = stmt->next;
} else {
if (stmt->kind == ND_LABEL && stmt->lhs) {
stmt = stmt->lhs;
} else {
break;
}
}
}
if (stmt->kind == ND_EXPR_STMT) {
node->ty = stmt->lhs->ty;
return;