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

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