Skip to content

compiler: threaded codegen (and more goodies) #24124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
424e6ac
compiler: minor refactors to ZCU linking
mlugg May 27, 2025
3743c3e
compiler: slightly untangle LLVM from the linkers
mlugg May 28, 2025
2fb6f5c
link: divorce LLD from the self-hosted linkers
mlugg May 28, 2025
66d15d9
link: make checking for failed types the responsibility of Compilation
mlugg May 29, 2025
9eb400e
compiler: rework backend pipeline to separate codegen and link
mlugg May 29, 2025
5ab307c
compiler: get most backends compiling again
mlugg Jun 1, 2025
c0df707
wasm: get self-hosted compiling, and supporting `separate_thread`
mlugg Jun 3, 2025
89ba885
spirv: make the backend compile again
mlugg Jun 3, 2025
808c15d
link.Lld: remove dead caching logic
mlugg Jun 6, 2025
b5f73f8
compiler: rework emit paths and cache modes
mlugg Jun 6, 2025
d24af29
CMakeLists: update file list
mlugg Jun 6, 2025
580d622
Zcu: fix verbose air
jacobly0 Jun 7, 2025
c4ec382
InternPool: store the Nav types are named after
mlugg Jun 7, 2025
c95b1bf
x86_64: remove air references from mir
jacobly0 Jun 7, 2025
ba53b14
x86_64: remove linker references from codegen
jacobly0 Jun 8, 2025
db5d85b
compiler: improve progress output
mlugg Jun 8, 2025
ac745ed
compiler: estimate totals for "Code Generation" and "Linking" progres…
mlugg Jun 8, 2025
e28b699
libs: fix caching behavior
mlugg Jun 8, 2025
89a6c73
Zcu: fix `deleteExport` crash with LLVM backend
mlugg Jun 8, 2025
a3abaae
test-link: correct expected object file name
mlugg Jun 8, 2025
5611969
x86_64: fix `dbg_var_ptr` types in debug info
jacobly0 Jun 9, 2025
d312dfc
codegen: make threadlocal logic consistent
jacobly0 Jun 9, 2025
7461370
Sema: fix union layout logic to match struct layout logic
jacobly0 Jun 9, 2025
afa07f7
x86_64: implement coff relocations
jacobly0 Jun 9, 2025
22e9610
link: fix goff and xcoff flush
mlugg Jun 11, 2025
7f2f107
Zcu: SPIR-V also doesn't generate MIR (yet)
mlugg Jun 11, 2025
1b27369
cli: correctly error for missing output directories
mlugg Jun 11, 2025
ff89a98
link.Queue: release safety lock before releasing mutex after stopping
mlugg Jun 11, 2025
4d2b216
test-stack-traces: correct expected object file name
jacobly0 Jun 11, 2025
d7afd79
Zcu: handle unreferenced `test_functions` correctly
mlugg Jun 11, 2025
de69d63
stage1: elaborate on "unimplemented" in wasi.c
mlugg Jun 11, 2025
f9a670d
Compilation: prevent zig1 depending on fd_readdir
mlugg Jun 11, 2025
5bb5aaf
compiler: don't queue too much AIR/MIR
mlugg Jun 12, 2025
71baa5e
compiler: improve progress output
mlugg Jun 12, 2025
43d01ff
x86_64.Lower: replace slow stringToEnum call
mlugg Jun 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,6 @@ set(ZIG_STAGE2_SOURCES
src/Sema.zig
src/Sema/bitcast.zig
src/Sema/comptime_ptr_access.zig
src/ThreadSafeQueue.zig
src/Type.zig
src/Value.zig
src/Zcu.zig
Expand Down Expand Up @@ -624,6 +623,7 @@ set(ZIG_STAGE2_SOURCES
src/link/Elf/synthetic_sections.zig
src/link/Goff.zig
src/link/LdScript.zig
src/link/Lld.zig
src/link/MachO.zig
src/link/MachO/Archive.zig
src/link/MachO/Atom.zig
Expand Down Expand Up @@ -652,6 +652,7 @@ set(ZIG_STAGE2_SOURCES
src/link/MachO/uuid.zig
src/link/Plan9.zig
src/link/Plan9/aout.zig
src/link/Queue.zig
src/link/SpirV.zig
src/link/SpirV/BinaryModule.zig
src/link/SpirV/deduplicate.zig
Expand Down
66 changes: 25 additions & 41 deletions lib/std/Build/Step/Compile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1834,47 +1834,16 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
lp.path = b.fmt("{}", .{output_dir});
}

// -femit-bin[=path] (default) Output machine code
if (compile.generated_bin) |bin| {
bin.path = output_dir.joinString(b.allocator, compile.out_filename) catch @panic("OOM");
}

const sep = std.fs.path.sep_str;

// output PDB if someone requested it
if (compile.generated_pdb) |pdb| {
pdb.path = b.fmt("{}" ++ sep ++ "{s}.pdb", .{ output_dir, compile.name });
}

// -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
if (compile.generated_implib) |implib| {
implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name });
}

// -femit-h[=path] Generate a C header file (.h)
if (compile.generated_h) |lp| {
lp.path = b.fmt("{}" ++ sep ++ "{s}.h", .{ output_dir, compile.name });
}

// -femit-docs[=path] Create a docs/ dir with html documentation
if (compile.generated_docs) |generated_docs| {
generated_docs.path = output_dir.joinString(b.allocator, "docs") catch @panic("OOM");
}

// -femit-asm[=path] Output .s (assembly code)
if (compile.generated_asm) |lp| {
lp.path = b.fmt("{}" ++ sep ++ "{s}.s", .{ output_dir, compile.name });
}

// -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
if (compile.generated_llvm_ir) |lp| {
lp.path = b.fmt("{}" ++ sep ++ "{s}.ll", .{ output_dir, compile.name });
}

// -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
if (compile.generated_llvm_bc) |lp| {
lp.path = b.fmt("{}" ++ sep ++ "{s}.bc", .{ output_dir, compile.name });
}
// zig fmt: off
if (compile.generated_bin) |lp| lp.path = compile.outputPath(output_dir, .bin);
if (compile.generated_pdb) |lp| lp.path = compile.outputPath(output_dir, .pdb);
if (compile.generated_implib) |lp| lp.path = compile.outputPath(output_dir, .implib);
if (compile.generated_h) |lp| lp.path = compile.outputPath(output_dir, .h);
if (compile.generated_docs) |lp| lp.path = compile.outputPath(output_dir, .docs);
if (compile.generated_asm) |lp| lp.path = compile.outputPath(output_dir, .@"asm");
if (compile.generated_llvm_ir) |lp| lp.path = compile.outputPath(output_dir, .llvm_ir);
if (compile.generated_llvm_bc) |lp| lp.path = compile.outputPath(output_dir, .llvm_bc);
// zig fmt: on
}

if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic and
Expand All @@ -1888,6 +1857,21 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
);
}
}
fn outputPath(c: *Compile, out_dir: std.Build.Cache.Path, ea: std.zig.EmitArtifact) []const u8 {
const arena = c.step.owner.graph.arena;
const name = ea.cacheName(arena, .{
.root_name = c.name,
.target = c.root_module.resolved_target.?.result,
.output_mode = switch (c.kind) {
.lib => .Lib,
.obj, .test_obj => .Obj,
.exe, .@"test" => .Exe,
},
.link_mode = c.linkage,
.version = c.version,
}) catch @panic("OOM");
return out_dir.joinString(arena, name) catch @panic("OOM");
}

pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) !Path {
const gpa = c.step.owner.allocator;
Expand Down
22 changes: 22 additions & 0 deletions lib/std/Progress.zig
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,28 @@ pub const Node = struct {
_ = @atomicRmw(u32, &storage.completed_count, .Add, 1, .monotonic);
}

/// Thread-safe. Bytes after '0' in `new_name` are ignored.
pub fn setName(n: Node, new_name: []const u8) void {
const index = n.index.unwrap() orelse return;
const storage = storageByIndex(index);

const name_len = @min(max_name_len, std.mem.indexOfScalar(u8, new_name, 0) orelse new_name.len);

copyAtomicStore(storage.name[0..name_len], new_name[0..name_len]);
if (name_len < storage.name.len)
@atomicStore(u8, &storage.name[name_len], 0, .monotonic);
}

/// Gets the name of this `Node`.
/// A pointer to this array can later be passed to `setName` to restore the name.
pub fn getName(n: Node) [max_name_len]u8 {
var dest: [max_name_len]u8 align(@alignOf(usize)) = undefined;
if (n.index.unwrap()) |index| {
copyAtomicLoad(&dest, &storageByIndex(index).name);
}
return dest;
}

/// Thread-safe.
pub fn setCompletedItems(n: Node, completed_items: usize) void {
const index = n.index.unwrap() orelse return;
Expand Down
4 changes: 2 additions & 2 deletions lib/std/heap/debug_allocator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ pub fn DebugAllocator(comptime config: Config) type {
DummyMutex{};

const DummyMutex = struct {
inline fn lock(_: *DummyMutex) void {}
inline fn unlock(_: *DummyMutex) void {}
inline fn lock(_: DummyMutex) void {}
inline fn unlock(_: DummyMutex) void {}
};

const stack_n = config.stack_trace_frames;
Expand Down
16 changes: 16 additions & 0 deletions lib/std/multi_array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ pub fn MultiArrayList(comptime T: type) type {
self.* = undefined;
}

/// Returns a `Slice` representing a range of elements in `s`, analagous to `arr[off..len]`.
/// It is illegal to call `deinit` or `toMultiArrayList` on the returned `Slice`.
/// Asserts that `off + len <= s.len`.
pub fn subslice(s: Slice, off: usize, len: usize) Slice {
assert(off + len <= s.len);
var ptrs: [fields.len][*]u8 = undefined;
inline for (s.ptrs, &ptrs, fields) |in, *out, field| {
out.* = in + (off * @sizeOf(field.type));
}
return .{
.ptrs = ptrs,
.len = len,
.capacity = len,
};
}

/// This function is used in the debugger pretty formatters in tools/ to fetch the
/// child field order and entry type to facilitate fancy debug printing for this type.
fn dbHelper(self: *Slice, child: *Elem, field: *Field, entry: *Entry) void {
Expand Down
29 changes: 29 additions & 0 deletions lib/std/zig.zig
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,35 @@ pub const SimpleComptimeReason = enum(u32) {
}
};

/// Every kind of artifact which the compiler can emit.
pub const EmitArtifact = enum {
bin,
@"asm",
implib,
llvm_ir,
llvm_bc,
docs,
pdb,
h,

/// If using `Server` to communicate with the compiler, it will place requested artifacts in
/// paths under the output directory, where those paths are named according to this function.
/// Returned string is allocated with `gpa` and owned by the caller.
pub fn cacheName(ea: EmitArtifact, gpa: Allocator, opts: BinNameOptions) Allocator.Error![]const u8 {
const suffix: []const u8 = switch (ea) {
.bin => return binNameAlloc(gpa, opts),
.@"asm" => ".s",
.implib => ".lib",
.llvm_ir => ".ll",
.llvm_bc => ".bc",
.docs => "-docs",
.pdb => ".pdb",
.h => ".h",
};
return std.fmt.allocPrint(gpa, "{s}{s}", .{ opts.root_name, suffix });
}
};

test {
_ = Ast;
_ = AstRlAnnotate;
Expand Down
9 changes: 9 additions & 0 deletions lib/std/zig/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4861,6 +4861,15 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
}
}

pub fn getParamName(zir: Zir, param_inst: Inst.Index) ?NullTerminatedString {
const inst = zir.instructions.get(@intFromEnum(param_inst));
return switch (inst.tag) {
.param, .param_comptime => zir.extraData(Inst.Param, inst.data.pl_tok.payload_index).data.name,
.param_anytype, .param_anytype_comptime => inst.data.str_tok.start,
else => null,
};
}

pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
Expand Down
4 changes: 1 addition & 3 deletions src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1153,9 +1153,7 @@ pub const Inst = struct {
ty: Type,
arg: struct {
ty: Ref,
/// Index into `extra` of a null-terminated string representing the parameter name.
/// This is `.none` if debug info is stripped.
name: NullTerminatedString,
zir_param_index: u32,
},
ty_op: struct {
ty: Ref,
Expand Down
5 changes: 1 addition & 4 deletions src/Air/print.zig
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,7 @@ const Writer = struct {
fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
try w.writeType(s, arg.ty.toType());
switch (arg.name) {
.none => {},
_ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
}
try s.print(", {d}", .{arg.zir_param_index});
}

fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
Expand Down
Loading
Loading