Skip to content

Commit

Permalink
Merge pull request ziglang#7598 from FireFox317/more-llvm-stage2
Browse files Browse the repository at this point in the history
stage2: More improvements to self-hosted LLVM backend
  • Loading branch information
andrewrk authored Jan 4, 2021
2 parents 5cc1310 + 0151f3b commit f664425
Show file tree
Hide file tree
Showing 12 changed files with 497 additions and 162 deletions.
200 changes: 111 additions & 89 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub fn build(b: *Builder) !void {
exe.addBuildOption(bool, "have_llvm", enable_llvm);
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);

if (is_stage1) {
exe.addIncludeDir("src");
exe.addIncludeDir("deps/SoftFloat-3e/source/include");
Expand All @@ -109,28 +110,8 @@ pub fn build(b: *Builder) !void {
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
exe.linkLibrary(softfloat);

const exe_cflags = [_][]const u8{
"-std=c++14",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D__STDC_LIMIT_MACROS",
"-D_GNU_SOURCE",
"-fvisibility-inlines-hidden",
"-fno-exceptions",
"-fno-rtti",
"-Werror=type-limits",
"-Wno-missing-braces",
"-Wno-comment",
};
exe.addCSourceFiles(&stage1_sources, &exe_cflags);
exe.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
if (cmake_cfg == null) {
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
// in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
// unavailable when LLVM is compiled in Release mode.
const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
}
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
Expand All @@ -139,79 +120,14 @@ pub fn build(b: *Builder) !void {
if (cfg.cmake_prefix_path.len > 0) {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
cfg.cmake_binary_dir,
"zigcpp",
b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
}) catch unreachable);
assert(cfg.lld_include_dir.len != 0);
exe.addIncludeDir(cfg.lld_include_dir);
addCMakeLibraryList(exe, cfg.clang_libraries);
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);

const need_cpp_includes = tracy != null;

// System -lc++ must be used because in this code path we are attempting to link
// against system-provided LLVM, Clang, LLD.
if (exe.target.getOsTag() == .linux) {
// First we try to static link against gcc libstdc++. If that doesn't work,
// we fall back to -lc++ and cross our fingers.
addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
error.RequiredLibraryNotFound => {
exe.linkSystemLibrary("c++");
},
else => |e| return e,
};

exe.linkSystemLibrary("pthread");
} else if (exe.target.isFreeBSD()) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
} else if (exe.target.getOsTag() == .openbsd) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
} else if (exe.target.isDarwin()) {
if (addCxxKnownPath(b, cfg, exe, "libgcc_eh.a", "", need_cpp_includes)) {
// Compiler is GCC.
try addCxxKnownPath(b, cfg, exe, "libstdc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
// TODO LLD cannot perform this link.
// Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead.
// See https://github.com/ziglang/zig/issues/1535
} else |err| switch (err) {
error.RequiredLibraryNotFound => {
// System compiler, not gcc.
exe.linkSystemLibrary("c++");
},
else => |e| return e,
}
}

if (cfg.dia_guids_lib.len != 0) {
exe.addObjectFile(cfg.dia_guids_lib);
}
try addCmakeCfgOptionsToExe(b, cfg, tracy, exe);
try addCmakeCfgOptionsToExe(b, cfg, tracy, test_stage2);
} else {
// Here we are -Denable-llvm but no cmake integration.
for (clang_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

for (lld_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

for (llvm_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");

if (target.getOs().tag == .windows) {
exe.linkSystemLibrary("version");
exe.linkSystemLibrary("uuid");
}
try addStaticLlvmOptionsToExe(exe);
try addStaticLlvmOptionsToExe(test_stage2);
}
}
if (link_libc) {
Expand Down Expand Up @@ -357,6 +273,112 @@ pub fn build(b: *Builder) !void {
test_step.dependOn(docs_step);
}

const exe_cflags = [_][]const u8{
"-std=c++14",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D__STDC_LIMIT_MACROS",
"-D_GNU_SOURCE",
"-fvisibility-inlines-hidden",
"-fno-exceptions",
"-fno-rtti",
"-Werror=type-limits",
"-Wno-missing-braces",
"-Wno-comment",
};

fn addCmakeCfgOptionsToExe(
b: *Builder,
cfg: CMakeConfig,
tracy: ?[]const u8,
exe: *std.build.LibExeObjStep,
) !void {
exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
cfg.cmake_binary_dir,
"zigcpp",
b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
}) catch unreachable);
assert(cfg.lld_include_dir.len != 0);
exe.addIncludeDir(cfg.lld_include_dir);
addCMakeLibraryList(exe, cfg.clang_libraries);
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);

const need_cpp_includes = tracy != null;

// System -lc++ must be used because in this code path we are attempting to link
// against system-provided LLVM, Clang, LLD.
if (exe.target.getOsTag() == .linux) {
// First we try to static link against gcc libstdc++. If that doesn't work,
// we fall back to -lc++ and cross our fingers.
addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
error.RequiredLibraryNotFound => {
exe.linkSystemLibrary("c++");
},
else => |e| return e,
};

exe.linkSystemLibrary("pthread");
} else if (exe.target.isFreeBSD()) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
} else if (exe.target.getOsTag() == .openbsd) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
} else if (exe.target.isDarwin()) {
if (addCxxKnownPath(b, cfg, exe, "libgcc_eh.a", "", need_cpp_includes)) {
// Compiler is GCC.
try addCxxKnownPath(b, cfg, exe, "libstdc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
// TODO LLD cannot perform this link.
// Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead.
// See https://github.com/ziglang/zig/issues/1535
} else |err| switch (err) {
error.RequiredLibraryNotFound => {
// System compiler, not gcc.
exe.linkSystemLibrary("c++");
},
else => |e| return e,
}
}

if (cfg.dia_guids_lib.len != 0) {
exe.addObjectFile(cfg.dia_guids_lib);
}
}

fn addStaticLlvmOptionsToExe(
exe: *std.build.LibExeObjStep,
) !void {
// Adds the Zig C++ sources which both stage1 and stage2 need.
//
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
// in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
// unavailable when LLVM is compiled in Release mode.
const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);

for (clang_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

for (lld_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

for (llvm_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}

// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");

if (exe.target.getOs().tag == .windows) {
exe.linkSystemLibrary("version");
exe.linkSystemLibrary("uuid");
}
}

fn addCxxKnownPath(
b: *Builder,
ctx: CMakeConfig,
Expand Down
3 changes: 2 additions & 1 deletion src/Cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const Allocator = std.mem.Allocator;
/// This protection is conditionally compiled depending on `want_debug_deadlock`.
var all_cache_digest_set: std.AutoHashMapUnmanaged(BinDigest, void) = .{};
var all_cache_digest_lock: std.Mutex = .{};
const want_debug_deadlock = std.debug.runtime_safety;
// TODO: Figure out how to make sure that `all_cache_digest_set` does not leak memory!
pub const want_debug_deadlock = false;
const DebugBinDigest = if (want_debug_deadlock) BinDigest else void;
const null_debug_bin_digest = if (want_debug_deadlock) ([1]u8{0} ** bin_digest_len) else {};

Expand Down
5 changes: 5 additions & 0 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,7 @@ pub fn destroy(self: *Compilation) void {

const gpa = self.gpa;
self.work_queue.deinit();
self.c_object_work_queue.deinit();

{
var it = self.crt_files.iterator();
Expand Down Expand Up @@ -1202,6 +1203,10 @@ pub fn destroy(self: *Compilation) void {
crt_file.deinit(gpa);
}

if (self.glibc_so_files) |*glibc_file| {
glibc_file.deinit(gpa);
}

for (self.c_object_table.items()) |entry| {
entry.key.destroy(gpa);
}
Expand Down
2 changes: 1 addition & 1 deletion src/DepTokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
try out.writeAll("\n");
try printSection(out, "<<<< input", input);
try printSection(out, "==== expect", expect);
try printSection(out, ">>>> got", got);
try printSection(out, ">>>> got", buffer.items);
try printRuler(out);

testing.expect(false);
Expand Down
7 changes: 5 additions & 2 deletions src/link/Coff.zig
Original file line number Diff line number Diff line change
Expand Up @@ -811,8 +811,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
if (use_stage1) {
// Both stage1 and stage2 LLVM backend put the object file in the cache directory.
if (self.base.options.use_llvm) {
// Stage2 has to call flushModule since that outputs the LLVM object file.
if (!build_options.is_stage1) try self.flushModule(comp);

const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
.target = self.base.options.target,
Expand Down
7 changes: 5 additions & 2 deletions src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1251,8 +1251,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
if (use_stage1) {
// Both stage1 and stage2 LLVM backend put the object file in the cache directory.
if (self.base.options.use_llvm) {
// Stage2 has to call flushModule since that outputs the LLVM object file.
if (!build_options.is_stage1) try self.flushModule(comp);

const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
.target = self.base.options.target,
Expand Down
Loading

0 comments on commit f664425

Please sign in to comment.