Merge remote-tracking branch 'origin/master' into llvm8

This commit is contained in:
Andrew Kelley
2019-03-13 12:56:58 -04:00
4019 changed files with 411936 additions and 244 deletions

View File

@@ -10,7 +10,7 @@
#include "codegen.hpp"
#include "analyze.hpp"
#include "compiler.hpp"
#include "install_files.h"
struct LinkJob {
CodeGen *codegen;
@@ -53,6 +53,10 @@ static bool target_is_glibc(CodeGen *g) {
return g->zig_target->os == OsLinux && target_abi_is_gnu(g->zig_target->abi);
}
static bool target_is_musl(CodeGen *g) {
return g->zig_target->os == OsLinux && target_abi_is_musl(g->zig_target->abi);
}
static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) {
CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str(name));
@@ -63,6 +67,14 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil
return buf_ptr(&child_gen->output_file_path);
}
static const char *build_asm_object(CodeGen *parent_gen, const char *name, Buf *file) {
CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str(name));
codegen_add_assembly(child_gen, file);
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
}
static const char *path_from_zig_lib(CodeGen *g, const char *dir, const char *subpath) {
Buf *dir1 = buf_alloc();
os_path_join(g->zig_lib_dir, buf_create_from_str(dir), dir1);
@@ -366,6 +378,233 @@ static const char *glibc_start_asm_path(CodeGen *parent, const char *file) {
return buf_ptr(&result);
}
static const char *musl_arch_name(const ZigTarget *target) {
switch (target->arch) {
case ZigLLVM_aarch64:
case ZigLLVM_aarch64_be:
return "aarch64";
case ZigLLVM_arm:
case ZigLLVM_armeb:
return "arm";
case ZigLLVM_mips:
case ZigLLVM_mipsel:
return "mips";
case ZigLLVM_mips64el:
case ZigLLVM_mips64:
return "mips64";
case ZigLLVM_ppc:
return "powerpc";
case ZigLLVM_ppc64:
case ZigLLVM_ppc64le:
return "powerpc64";
case ZigLLVM_systemz:
return "s390x";
case ZigLLVM_x86:
return "i386";
case ZigLLVM_x86_64:
return "x86_64";
default:
zig_unreachable();
}
}
static Buf *musl_start_asm_path(CodeGen *parent, const char *file) {
return buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "crt" OS_SEP "%s" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), musl_arch_name(parent->zig_target), file);
}
static void musl_add_cc_args(CodeGen *parent, CFile *c_file) {
c_file->args.append("-std=c99");
c_file->args.append("-ffreestanding");
// Musl adds these args to builds with gcc but clang does not support them.
//c_file->args.append("-fexcess-precision=standard");
//c_file->args.append("-frounding-math");
c_file->args.append("-Wa,--noexecstack");
c_file->args.append("-D_XOPEN_SOURCE=700");
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), musl_arch_name(parent->zig_target))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "generic",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "internal",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "include",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf(
"%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-%s-%s",
buf_ptr(parent->zig_lib_dir),
target_arch_name(parent->zig_target->arch),
target_os_name(parent->zig_target->os),
target_abi_name(parent->zig_target->abi))));
c_file->args.append("-I");
c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "generic-musl",
buf_ptr(parent->zig_lib_dir))));
c_file->args.append("-Os");
c_file->args.append("-fomit-frame-pointer");
c_file->args.append("-fno-unwind-tables");
c_file->args.append("-fno-asynchronous-unwind-tables");
c_file->args.append("-ffunction-sections");
c_file->args.append("-fdata-sections");
}
static const char *musl_arch_names[] = {
"aarch64",
"arm",
"generic",
"i386",
"m68k",
"microblaze",
"mips",
"mips64",
"mipsn32",
"or1k",
"powerpc",
"powerpc64",
"s390x",
"sh",
"x32",
"x86_64",
};
static bool is_musl_arch_name(const char *name) {
for (size_t i = 0; i < array_length(musl_arch_names); i += 1) {
if (strcmp(name, musl_arch_names[i]) == 0)
return true;
}
return false;
}
static const char *build_musl(CodeGen *parent) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
codegen_set_out_name(child_gen, buf_create_from_str("c"));
child_gen->is_static = true;
// When there is a src/<arch>/foo.* then it should substitute for src/foo.*
// Even a .s file can substitute for a .c file.
enum MuslSrc {
MuslSrcAsm,
MuslSrcNormal,
MuslSrcO3,
};
const char *target_musl_arch_name = musl_arch_name(parent->zig_target);
HashMap<Buf *, MuslSrc, buf_hash, buf_eql_buf> source_table = {};
source_table.init(1800);
for (size_t i = 0; i < array_length(ZIG_MUSL_SRC_FILES); i += 1) {
Buf *src_file = buf_create_from_str(ZIG_MUSL_SRC_FILES[i]);
MuslSrc src_kind;
if (buf_ends_with_str(src_file, ".c")) {
assert(buf_starts_with_str(src_file, "musl/src/"));
bool want_O3 = buf_starts_with_str(src_file, "musl/src/malloc/") ||
buf_starts_with_str(src_file, "musl/src/string/") ||
buf_starts_with_str(src_file, "musl/src/internal/");
src_kind = want_O3 ? MuslSrcO3 : MuslSrcNormal;
} else if (buf_ends_with_str(src_file, ".s") || buf_ends_with_str(src_file, ".S")) {
src_kind = MuslSrcAsm;
} else {
continue;
}
if (ZIG_OS_SEP_CHAR != '/') {
buf_replace(src_file, '/', ZIG_OS_SEP_CHAR);
}
source_table.put_unique(src_file, src_kind);
}
ZigList<CFile *> c_source_files = {0};
Buf dirname = BUF_INIT;
Buf basename = BUF_INIT;
Buf noextbasename = BUF_INIT;
Buf dirbasename = BUF_INIT;
Buf before_arch_dir = BUF_INIT;
Buf override_c = BUF_INIT;
Buf override_s = BUF_INIT;
Buf override_S = BUF_INIT;
auto source_it = source_table.entry_iterator();
for (;;) {
auto *entry = source_it.next();
if (!entry) break;
Buf *src_file = entry->key;
MuslSrc src_kind = entry->value;
os_path_split(src_file, &dirname, &basename);
os_path_extname(&basename, &noextbasename, nullptr);
os_path_split(&dirname, &before_arch_dir, &dirbasename);
if (is_musl_arch_name(buf_ptr(&dirbasename))) {
// We find these by explicitly looking for overrides.
continue;
}
// Look for an arch specific override.
buf_resize(&override_c, 0);
buf_resize(&override_s, 0);
buf_resize(&override_S, 0);
buf_appendf(&override_c, "%s" OS_SEP "%s" OS_SEP "%s.c",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
buf_appendf(&override_s, "%s" OS_SEP "%s" OS_SEP "%s.s",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
buf_appendf(&override_S, "%s" OS_SEP "%s" OS_SEP "%s.S",
buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename));
if (source_table.maybe_get(&override_c) != nullptr) {
src_file = &override_c;
src_kind = (src_kind == MuslSrcAsm) ? MuslSrcNormal : src_kind;
} else if (source_table.maybe_get(&override_s) != nullptr) {
src_file = &override_s;
src_kind = MuslSrcAsm;
} else if (source_table.maybe_get(&override_S) != nullptr) {
src_file = &override_S;
src_kind = MuslSrcAsm;
}
Buf *full_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "%s",
buf_ptr(parent->zig_lib_dir), buf_ptr(src_file));
if (src_kind == MuslSrcAsm) {
codegen_add_assembly(child_gen, full_path);
} else {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = buf_ptr(full_path);
musl_add_cc_args(parent, c_file);
c_file->args.append("-Wno-ignored-attributes");
c_file->args.append("-Wno-bitwise-op-parentheses");
c_file->args.append("-Wno-logical-op-parentheses");
c_file->args.append("-Wno-dangling-else");
c_file->args.append("-Wno-shift-op-parentheses");
c_file->args.append("-Qunused-arguments");
c_file->args.append("-Wno-unknown-pragmas");
c_file->args.append("-Wno-string-plus-int");
c_file->args.append("-Wno-parentheses");
if (src_kind == MuslSrcO3) {
c_file->args.append("-O3");
}
c_source_files.append(c_file);
}
}
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
}
static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
if (parent->libc == nullptr && target_is_glibc(parent)) {
if (strcmp(file, "crti.o") == 0) {
@@ -514,6 +753,29 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
} else {
zig_unreachable();
}
} else if (parent->libc == nullptr && target_is_musl(parent)) {
if (strcmp(file, "crti.o") == 0) {
return build_asm_object(parent, "crti", musl_start_asm_path(parent, "crti.s"));
} else if (strcmp(file, "crtn.o") == 0) {
return build_asm_object(parent, "crtn", musl_start_asm_path(parent, "crtn.s"));
} else if (strcmp(file, "crt1.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "crt1.c");
musl_add_cc_args(parent, c_file);
c_file->args.append("-fno-stack-protector");
c_file->args.append("-DCRT");
return build_libc_object(parent, "crt1", c_file);
} else if (strcmp(file, "Scrt1.o") == 0) {
CFile *c_file = allocate<CFile>(1);
c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "Scrt1.c");
musl_add_cc_args(parent, c_file);
c_file->args.append("-fPIC");
c_file->args.append("-fno-stack-protector");
c_file->args.append("-DCRT");
return build_libc_object(parent, "Scrt1", c_file);
} else {
zig_unreachable();
}
} else {
assert(parent->libc != nullptr);
Buf *out_buf = buf_alloc();
@@ -770,7 +1032,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
// libc is linked specially
continue;
}
if (g->libc == nullptr && target_is_glibc(g)) {
if (g->libc == nullptr && (target_is_glibc(g) || target_is_musl(g))) {
// these libraries are always linked below when targeting glibc
if (buf_eql_str(link_lib->name, "m")) {
continue;
@@ -796,24 +1058,26 @@ static void construct_linker_job_elf(LinkJob *lj) {
// libc dep
if (g->libc_link_lib != nullptr) {
if (g->is_static) {
lj->args.append("--start-group");
lj->args.append("-lgcc");
lj->args.append("-lgcc_eh");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("--end-group");
} else if (g->libc != nullptr) {
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
if (g->libc != nullptr) {
if (g->is_static) {
lj->args.append("--start-group");
lj->args.append("-lgcc");
lj->args.append("-lgcc_eh");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("--end-group");
} else {
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
lj->args.append("-lc");
lj->args.append("-lm");
lj->args.append("-lgcc");
lj->args.append("--as-needed");
lj->args.append("-lgcc_s");
lj->args.append("--no-as-needed");
}
} else if (target_is_glibc(g)) {
lj->args.append(build_libunwind(g));
lj->args.append(build_dummy_so(g, "c", 6));
@@ -822,6 +1086,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
lj->args.append(build_dummy_so(g, "dl", 2));
lj->args.append(build_dummy_so(g, "rt", 1));
lj->args.append(get_libc_crt_file(g, "libc_nonshared.a"));
} else if (target_is_musl(g)) {
lj->args.append(build_libunwind(g));
lj->args.append(build_musl(g));
} else {
zig_unreachable();
}