authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-30 01:26:00-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-30 01:26:00-07:00
log937e8cb7051a3de537e11c2d52946f772f7449c3
tree94d5b2cc7c19a9a16fd13099e10249ef64278b8f
parent873c695c41dffd89ba7ef1b3ed6662e429bfa00d
parent864bb5dc075fdc549e116b93914f30bff8cc7cf5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17328 from ziglang/simplify-cbe-deps

C backend: remove unneeded ordering mechanism

3 files changed, 42 insertions(+), 58 deletions(-)

src/Compilation.zig+1-1
......@@ -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+27-21
......@@ -522,8 +522,8 @@ pub const Object = struct {
522522pub 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
46394644fn 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
46844688fn 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
71967199fn 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+14-36
......@@ -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
386376const 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.
595581fn 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