Skip to content

Commit 937e8cb

Browse files
authored
Merge pull request #17328 from ziglang/simplify-cbe-deps
C backend: remove unneeded ordering mechanism
2 parents 873c695 + 864bb5d commit 937e8cb

File tree

3 files changed

+42
-58
lines changed

3 files changed

+42
-58
lines changed

src/Compilation.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3495,7 +3495,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
34953495
.module = module,
34963496
.error_msg = null,
34973497
.decl_index = decl_index.toOptional(),
3498-
.decl = decl,
3498+
.is_naked_fn = false,
34993499
.fwd_decl = fwd_decl.toManaged(gpa),
35003500
.ctypes = .{},
35013501
};

src/codegen/c.zig

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ pub const Object = struct {
522522
pub const DeclGen = struct {
523523
gpa: mem.Allocator,
524524
module: *Module,
525-
decl: ?*Decl,
526525
decl_index: Decl.OptionalIndex,
526+
is_naked_fn: bool,
527527
/// This is a borrowed reference from `link.C`.
528528
fwd_decl: std.ArrayList(u8),
529529
error_msg: ?*Module.ErrorMsg,
@@ -532,8 +532,10 @@ pub const DeclGen = struct {
532532
fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
533533
@setCold(true);
534534
const mod = dg.module;
535+
const decl_index = dg.decl_index.unwrap().?;
536+
const decl = mod.declPtr(decl_index);
535537
const src = LazySrcLoc.nodeOffset(0);
536-
const src_loc = src.toSrcLoc(dg.decl.?, mod);
538+
const src_loc = src.toSrcLoc(decl, mod);
537539
dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
538540
return error.AnalysisFail;
539541
}
@@ -2493,8 +2495,8 @@ fn genExports(o: *Object) !void {
24932495

24942496
const mod = o.dg.module;
24952497
const ip = &mod.intern_pool;
2496-
const decl = o.dg.decl.?;
24972498
const decl_index = o.dg.decl_index.unwrap().?;
2499+
const decl = mod.declPtr(decl_index);
24982500
const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };
24992501
const fwd = o.dg.fwd_decl.writer();
25002502

@@ -2634,9 +2636,10 @@ pub fn genFunc(f: *Function) !void {
26342636
const mod = o.dg.module;
26352637
const gpa = o.dg.gpa;
26362638
const decl_index = o.dg.decl_index.unwrap().?;
2639+
const decl = mod.declPtr(decl_index);
26372640
const tv: TypedValue = .{
2638-
.ty = o.dg.decl.?.ty,
2639-
.val = o.dg.decl.?.val,
2641+
.ty = decl.ty,
2642+
.val = decl.val,
26402643
};
26412644

26422645
o.code_header = std.ArrayList(u8).init(gpa);
@@ -2719,19 +2722,20 @@ pub fn genDecl(o: *Object) !void {
27192722
defer tracy.end();
27202723

27212724
const mod = o.dg.module;
2722-
const decl = o.dg.decl.?;
2723-
const decl_c_value = .{ .decl = o.dg.decl_index.unwrap().? };
2725+
const decl_index = o.dg.decl_index.unwrap().?;
2726+
const decl_c_value = .{ .decl = decl_index };
2727+
const decl = mod.declPtr(decl_index);
27242728
const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };
27252729

27262730
if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return;
27272731
if (tv.val.getExternFunc(mod)) |_| {
27282732
const fwd_decl_writer = o.dg.fwd_decl.writer();
27292733
try fwd_decl_writer.writeAll("zig_extern ");
2730-
try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 });
2734+
try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
27312735
try fwd_decl_writer.writeAll(";\n");
27322736
try genExports(o);
27332737
} else if (tv.val.getVariable(mod)) |variable| {
2734-
try o.dg.renderFwdDecl(decl_c_value.decl, variable);
2738+
try o.dg.renderFwdDecl(decl_index, variable);
27352739
try genExports(o);
27362740

27372741
if (variable.is_extern) return;
@@ -2750,7 +2754,7 @@ pub fn genDecl(o: *Object) !void {
27502754
try w.writeByte(';');
27512755
try o.indent_writer.insertNewline();
27522756
} else {
2753-
const is_global = o.dg.module.decl_exports.contains(decl_c_value.decl);
2757+
const is_global = o.dg.module.decl_exports.contains(decl_index);
27542758
const fwd_decl_writer = o.dg.fwd_decl.writer();
27552759

27562760
try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
@@ -2773,12 +2777,14 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
27732777
const tracy = trace(@src());
27742778
defer tracy.end();
27752779

2780+
const mod = dg.module;
2781+
const decl_index = dg.decl_index.unwrap().?;
2782+
const decl = mod.declPtr(decl_index);
27762783
const tv: TypedValue = .{
2777-
.ty = dg.decl.?.ty,
2778-
.val = dg.decl.?.val,
2784+
.ty = decl.ty,
2785+
.val = decl.val,
27792786
};
27802787
const writer = dg.fwd_decl.writer();
2781-
const mod = dg.module;
27822788

27832789
switch (tv.ty.zigTypeTag(mod)) {
27842790
.Fn => {
@@ -3504,8 +3510,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
35043510
} else {
35053511
try reap(f, inst, &.{un_op});
35063512
// Not even allowed to return void in a naked function.
3507-
if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention(mod) != .Naked else true)
3508-
try writer.writeAll("return;\n");
3513+
if (!f.object.dg.is_naked_fn) try writer.writeAll("return;\n");
35093514
}
35103515
return .none;
35113516
}
@@ -4144,7 +4149,7 @@ fn airCall(
41444149
) !CValue {
41454150
const mod = f.object.dg.module;
41464151
// Not even allowed to call panic in a naked function.
4147-
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none;
4152+
if (f.object.dg.is_naked_fn) return .none;
41484153

41494154
const gpa = f.object.dg.gpa;
41504155
const writer = f.object.writer();
@@ -4637,9 +4642,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
46374642
}
46384643

46394644
fn airTrap(f: *Function, writer: anytype) !CValue {
4640-
const mod = f.object.dg.module;
46414645
// Not even allowed to call trap in a naked function.
4642-
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none;
4646+
if (f.object.dg.is_naked_fn) return .none;
46434647

46444648
try writer.writeAll("zig_trap();\n");
46454649
return .none;
@@ -4682,9 +4686,8 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
46824686
}
46834687

46844688
fn airUnreach(f: *Function) !CValue {
4685-
const mod = f.object.dg.module;
46864689
// Not even allowed to call unreachable in a naked function.
4687-
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none;
4690+
if (f.object.dg.is_naked_fn) return .none;
46884691

46894692
try f.object.writer().writeAll("zig_unreachable();\n");
46904693
return .none;
@@ -7194,8 +7197,11 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
71947197
}
71957198

71967199
fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
7200+
const mod = f.object.dg.module;
71977201
const inst_ty = f.typeOfIndex(inst);
7198-
const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
7202+
const decl_index = f.object.dg.decl_index.unwrap().?;
7203+
const decl = mod.declPtr(decl_index);
7204+
const fn_cty = try f.typeToCType(decl.ty, .complete);
71997205
const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
72007206

72017207
const writer = f.object.writer();

src/link/C.zig

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
139139

140140
const func = module.funcInfo(func_index);
141141
const decl_index = func.owner_decl;
142+
const decl = module.declPtr(decl_index);
142143
const gop = try self.decl_table.getOrPut(gpa, decl_index);
143144
if (!gop.found_existing) {
144145
gop.value_ptr.* = .{};
@@ -163,7 +164,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
163164
.module = module,
164165
.error_msg = null,
165166
.decl_index = decl_index.toOptional(),
166-
.decl = module.declPtr(decl_index),
167+
.is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
167168
.fwd_decl = fwd_decl.toManaged(gpa),
168169
.ctypes = ctypes.*,
169170
},
@@ -216,15 +217,13 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
216217
fwd_decl.clearRetainingCapacity();
217218
code.clearRetainingCapacity();
218219

219-
const decl = module.declPtr(decl_index);
220-
221220
var object: codegen.Object = .{
222221
.dg = .{
223222
.gpa = gpa,
224223
.module = module,
225224
.error_msg = null,
226225
.decl_index = decl_index.toOptional(),
227-
.decl = decl,
226+
.is_naked_fn = false,
228227
.fwd_decl = fwd_decl.toManaged(gpa),
229228
.ctypes = ctypes.*,
230229
},
@@ -322,29 +321,19 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
322321
self.lazy_code_buf.clearRetainingCapacity();
323322
try self.flushErrDecls(&f.lazy_ctypes);
324323

324+
// Unlike other backends, the .c code we are emitting has order-dependent decls.
325325
// `CType`s, forward decls, and non-functions first.
326-
// Unlike other backends, the .c code we are emitting is order-dependent. Therefore
327-
// we must traverse the set of Decls that we are emitting according to their dependencies.
328-
// Our strategy is to populate a set of remaining decls, pop Decls one by one,
329-
// recursively chasing their dependencies.
330-
try f.remaining_decls.ensureUnusedCapacity(gpa, self.decl_table.count());
331-
332-
const decl_keys = self.decl_table.keys();
333-
const decl_values = self.decl_table.values();
334-
for (decl_keys) |decl_index| {
335-
assert(module.declPtr(decl_index).has_tv);
336-
f.remaining_decls.putAssumeCapacityNoClobber(decl_index, {});
337-
}
338326

339327
{
340328
var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
341329
defer export_names.deinit(gpa);
342-
try export_names.ensureTotalCapacity(gpa, @as(u32, @intCast(module.decl_exports.entries.len)));
330+
try export_names.ensureTotalCapacity(gpa, @intCast(module.decl_exports.entries.len));
343331
for (module.decl_exports.values()) |exports| for (exports.items) |@"export"|
344332
try export_names.put(gpa, @"export".opts.name, {});
345333

346-
while (f.remaining_decls.popOrNull()) |kv| {
347-
const decl_index = kv.key;
334+
const decl_keys = self.decl_table.keys();
335+
for (decl_keys) |decl_index| {
336+
assert(module.declPtr(decl_index).has_tv);
348337
try self.flushDecl(&f, decl_index, export_names);
349338
}
350339
}
@@ -355,9 +344,9 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
355344
assert(f.ctypes.count() == 0);
356345
try self.flushCTypes(&f, .none, f.lazy_ctypes);
357346

358-
var it = self.decl_table.iterator();
359-
while (it.next()) |entry|
360-
try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
347+
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, db| {
348+
try self.flushCTypes(&f, decl_index.toOptional(), db.ctypes);
349+
}
361350
}
362351

363352
f.all_buffers.items[ctypes_index] = .{
@@ -374,6 +363,7 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
374363
f.file_size += lazy_fwd_decl_len;
375364

376365
// Now the code.
366+
const decl_values = self.decl_table.values();
377367
try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);
378368
f.appendBufAssumeCapacity(self.lazy_code_buf.items);
379369
for (decl_values) |decl| f.appendBufAssumeCapacity(self.getString(decl.code));
@@ -384,8 +374,6 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
384374
}
385375

386376
const Flush = struct {
387-
remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
388-
389377
ctypes: codegen.CType.Store = .{},
390378
ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
391379
ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
@@ -416,7 +404,6 @@ const Flush = struct {
416404
f.ctypes_buf.deinit(gpa);
417405
f.ctypes_map.deinit(gpa);
418406
f.ctypes.deinit(gpa);
419-
f.remaining_decls.deinit(gpa);
420407
}
421408
};
422409

@@ -522,7 +509,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
522509
.module = self.base.options.module.?,
523510
.error_msg = null,
524511
.decl_index = .none,
525-
.decl = null,
512+
.is_naked_fn = false,
526513
.fwd_decl = fwd_decl.toManaged(gpa),
527514
.ctypes = ctypes.*,
528515
},
@@ -556,7 +543,7 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa
556543
.module = self.base.options.module.?,
557544
.error_msg = null,
558545
.decl_index = .none,
559-
.decl = null,
546+
.is_naked_fn = false,
560547
.fwd_decl = fwd_decl.toManaged(gpa),
561548
.ctypes = ctypes.*,
562549
},
@@ -591,7 +578,6 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError
591578
}
592579
}
593580

594-
/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
595581
fn flushDecl(
596582
self: *C,
597583
f: *Flush,
@@ -601,14 +587,6 @@ fn flushDecl(
601587
const gpa = self.base.allocator;
602588
const mod = self.base.options.module.?;
603589
const decl = mod.declPtr(decl_index);
604-
// Before flushing any particular Decl we must ensure its
605-
// dependencies are already flushed, so that the order in the .c
606-
// file comes out correctly.
607-
for (decl.dependencies.keys()) |dep| {
608-
if (f.remaining_decls.swapRemove(dep)) {
609-
try flushDecl(self, f, dep, export_names);
610-
}
611-
}
612590

613591
const decl_block = self.decl_table.getPtr(decl_index).?;
614592

0 commit comments

Comments
 (0)