authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-27 21:47:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 12:12:51-07:00
log9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67
tree7c5fb8542a016e8a5b8054986d005b324d5f11bc
parentc0b55125443cab63945205b2f7c66bf12cae71e1

C backend: start handling anonymous decls

Start keeping track of dependencies on anon decls for dependency ordering during flush() Currently this causes use of undefined symbols because these dependencies need to get rendered into the output.

3 files changed, 133 insertions(+), 70 deletions(-)

src/Compilation.zig+1
......@@ -3499,6 +3499,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
34993499 .is_naked_fn = false,
35003500 .fwd_decl = fwd_decl.toManaged(gpa),
35013501 .ctypes = .{},
3502 .anon_decl_deps = .{},
35023503 };
35033504 defer {
35043505 dg.ctypes.deinit(gpa);
src/codegen/c.zig+60-24
......@@ -528,6 +528,9 @@ pub const DeclGen = struct {
528528 fwd_decl: std.ArrayList(u8),
529529 error_msg: ?*Module.ErrorMsg,
530530 ctypes: CType.Store,
531 /// Keeps track of anonymous decls that need to be rendered before this
532 /// (named) Decl in the output C code.
533 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
531534
532535 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
533536 @setCold(true);
......@@ -540,6 +543,57 @@ pub const DeclGen = struct {
540543 return error.AnalysisFail;
541544 }
542545
546 fn renderAnonDeclValue(
547 dg: *DeclGen,
548 writer: anytype,
549 ty: Type,
550 ptr_val: Value,
551 decl_val: InternPool.Index,
552 location: ValueRenderLocation,
553 ) error{ OutOfMemory, AnalysisFail }!void {
554 const mod = dg.module;
555 const ip = &mod.intern_pool;
556 const decl_ty = ip.typeOf(decl_val).toType();
557
558 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
559 if (ty.isPtrAtRuntime(mod) and !decl_ty.isFnOrHasRuntimeBits(mod)) {
560 return dg.writeCValue(writer, .{ .undef = ty });
561 }
562
563 // Chase function values in order to be able to reference the original function.
564 if (decl_val.toValue().getFunction(mod)) |func| {
565 _ = func;
566 _ = ptr_val;
567 _ = location;
568 @panic("TODO");
569 }
570 if (decl_val.toValue().getExternFunc(mod)) |extern_func| {
571 _ = extern_func;
572 _ = ptr_val;
573 _ = location;
574 @panic("TODO");
575 }
576
577 assert(decl_val.toValue().getVariable(mod) == null);
578
579 // We shouldn't cast C function pointers as this is UB (when you call
580 // them). The analysis until now should ensure that the C function
581 // pointers are compatible. If they are not, then there is a bug
582 // somewhere and we should let the C compiler tell us about it.
583 const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl_ty, mod);
584 if (need_typecast) {
585 try writer.writeAll("((");
586 try dg.renderType(writer, ty);
587 try writer.writeByte(')');
588 }
589 try writer.print("&__anon_{d}", .{@intFromEnum(decl_val)});
590 if (need_typecast) try writer.writeByte(')');
591
592 // Indicate that the anon decl should be rendered to the output so that
593 // our reference above is not undefined.
594 try dg.anon_decl_deps.put(dg.gpa, decl_val, {});
595 }
596
543597 fn renderDeclValue(
544598 dg: *DeclGen,
545599 writer: anytype,
......@@ -593,18 +647,9 @@ pub const DeclGen = struct {
593647 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);
594648 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;
595649 switch (ptr.addr) {
596 .decl, .mut_decl => try dg.renderDeclValue(
597 writer,
598 ptr_ty,
599 ptr_val.toValue(),
600 switch (ptr.addr) {
601 .decl => |decl| decl,
602 .mut_decl => |mut_decl| mut_decl.decl,
603 else => unreachable,
604 },
605 location,
606 ),
607 .anon_decl => @panic("TODO"),
650 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location),
651 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location),
652 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location),
608653 .int => |int| {
609654 try writer.writeByte('(');
610655 try dg.renderCType(writer, ptr_cty);
......@@ -1145,18 +1190,9 @@ pub const DeclGen = struct {
11451190 else => val.slicePtr(mod),
11461191 };
11471192 switch (ptr.addr) {
1148 .decl, .mut_decl => try dg.renderDeclValue(
1149 writer,
1150 ptr_ty,
1151 ptr_val,
1152 switch (ptr.addr) {
1153 .decl => |decl| decl,
1154 .mut_decl => |mut_decl| mut_decl.decl,
1155 else => unreachable,
1156 },
1157 ptr_location,
1158 ),
1159 .anon_decl => @panic("TODO"),
1193 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location),
1194 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location),
1195 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location),
11601196 .int => |int| {
11611197 try writer.writeAll("((");
11621198 try dg.renderType(writer, ptr_ty);
src/link/C.zig+72-46
......@@ -34,6 +34,9 @@ fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
3434/// Optimization, `updateDecl` reuses this buffer rather than creating a new
3535/// one with every call.
3636code_buf: std.ArrayListUnmanaged(u8) = .{},
37/// Optimization, `updateDecl` reuses this table rather than creating a new one
38/// with every call.
39scratch_anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
3740/// Optimization, `flush` reuses this buffer rather than creating a new
3841/// one with every call.
3942lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
......@@ -51,7 +54,6 @@ const String = struct {
5154 .len = 0,
5255 };
5356};
54
5557/// Per-declaration data.
5658const DeclBlock = struct {
5759 code: String = String.empty,
......@@ -98,7 +100,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
98100 var c_file = try gpa.create(C);
99101 errdefer gpa.destroy(c_file);
100102
101 c_file.* = C{
103 c_file.* = .{
102104 .base = .{
103105 .tag = .c,
104106 .options = options,
......@@ -121,6 +123,7 @@ pub fn deinit(self: *C) void {
121123 self.string_bytes.deinit(gpa);
122124 self.fwd_decl_buf.deinit(gpa);
123125 self.code_buf.deinit(gpa);
126 self.scratch_anon_decl_deps.deinit(gpa);
124127}
125128
126129pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
......@@ -131,10 +134,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
131134 }
132135}
133136
134pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
135 const tracy = trace(@src());
136 defer tracy.end();
137
137pub fn updateFunc(
138 self: *C,
139 module: *Module,
140 func_index: InternPool.Index,
141 air: Air,
142 liveness: Liveness,
143) !void {
138144 const gpa = self.base.allocator;
139145
140146 const func = module.funcInfo(func_index);
......@@ -152,52 +158,57 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
152158 lazy_fns.clearRetainingCapacity();
153159 fwd_decl.clearRetainingCapacity();
154160 code.clearRetainingCapacity();
161 self.scratch_anon_decl_deps.clearRetainingCapacity();
155162
156 var function: codegen.Function = .{
157 .value_map = codegen.CValueMap.init(gpa),
158 .air = air,
159 .liveness = liveness,
160 .func_index = func_index,
161 .object = .{
162 .dg = .{
163 .gpa = gpa,
164 .module = module,
165 .error_msg = null,
166 .decl_index = decl_index.toOptional(),
167 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
168 .fwd_decl = fwd_decl.toManaged(gpa),
169 .ctypes = ctypes.*,
163 {
164 var function: codegen.Function = .{
165 .value_map = codegen.CValueMap.init(gpa),
166 .air = air,
167 .liveness = liveness,
168 .func_index = func_index,
169 .object = .{
170 .dg = .{
171 .gpa = gpa,
172 .module = module,
173 .error_msg = null,
174 .decl_index = decl_index.toOptional(),
175 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
176 .fwd_decl = fwd_decl.toManaged(gpa),
177 .ctypes = ctypes.*,
178 .anon_decl_deps = self.scratch_anon_decl_deps,
179 },
180 .code = code.toManaged(gpa),
181 .indent_writer = undefined, // set later so we can get a pointer to object.code
170182 },
171 .code = code.toManaged(gpa),
172 .indent_writer = undefined, // set later so we can get a pointer to object.code
173 },
174 .lazy_fns = lazy_fns.*,
175 };
183 .lazy_fns = lazy_fns.*,
184 };
176185
177 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
178 defer {
179 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
180 code.* = function.object.code.moveToUnmanaged();
181 function.deinit();
182 }
186 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
187 defer {
188 self.scratch_anon_decl_deps = function.object.dg.anon_decl_deps;
189 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
190 code.* = function.object.code.moveToUnmanaged();
191 function.deinit();
192 }
183193
184 codegen.genFunc(&function) catch |err| switch (err) {
185 error.AnalysisFail => {
186 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
187 return;
188 },
189 else => |e| return e,
190 };
194 codegen.genFunc(&function) catch |err| switch (err) {
195 error.AnalysisFail => {
196 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
197 return;
198 },
199 else => |e| return e,
200 };
191201
192 ctypes.* = function.object.dg.ctypes.move();
193 lazy_fns.* = function.lazy_fns.move();
202 ctypes.* = function.object.dg.ctypes.move();
203 lazy_fns.* = function.lazy_fns.move();
194204
195 // Free excess allocated memory for this Decl.
196 ctypes.shrinkAndFree(gpa, ctypes.count());
197 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
205 // Free excess allocated memory for this Decl.
206 ctypes.shrinkAndFree(gpa, ctypes.count());
207 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
198208
199 gop.value_ptr.code = try self.addString(function.object.code.items);
200 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
209 gop.value_ptr.code = try self.addString(function.object.code.items);
210 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
211 }
201212}
202213
203214pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -216,6 +227,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
216227 ctypes.clearRetainingCapacity(gpa);
217228 fwd_decl.clearRetainingCapacity();
218229 code.clearRetainingCapacity();
230 self.scratch_anon_decl_deps.clearRetainingCapacity();
219231
220232 var object: codegen.Object = .{
221233 .dg = .{
......@@ -226,12 +238,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
226238 .is_naked_fn = false,
227239 .fwd_decl = fwd_decl.toManaged(gpa),
228240 .ctypes = ctypes.*,
241 .anon_decl_deps = self.scratch_anon_decl_deps,
229242 },
230243 .code = code.toManaged(gpa),
231244 .indent_writer = undefined, // set later so we can get a pointer to object.code
232245 };
233246 object.indent_writer = .{ .underlying_writer = object.code.writer() };
234247 defer {
248 self.scratch_anon_decl_deps = object.dg.anon_decl_deps;
235249 object.dg.ctypes.deinit(object.dg.gpa);
236250 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
237251 code.* = object.code.moveToUnmanaged();
......@@ -512,12 +526,16 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
512526 .is_naked_fn = false,
513527 .fwd_decl = fwd_decl.toManaged(gpa),
514528 .ctypes = ctypes.*,
529 .anon_decl_deps = .{},
515530 },
516531 .code = code.toManaged(gpa),
517532 .indent_writer = undefined, // set later so we can get a pointer to object.code
518533 };
519534 object.indent_writer = .{ .underlying_writer = object.code.writer() };
520535 defer {
536 // If this assert trips just handle the anon_decl_deps the same as
537 // `updateFunc()` does.
538 assert(object.dg.anon_decl_deps.count() == 0);
521539 object.dg.ctypes.deinit(gpa);
522540 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
523541 code.* = object.code.moveToUnmanaged();
......@@ -531,7 +549,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
531549 ctypes.* = object.dg.ctypes.move();
532550}
533551
534fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void {
552fn flushLazyFn(
553 self: *C,
554 ctypes: *codegen.CType.Store,
555 lazy_fn: codegen.LazyFnMap.Entry,
556) FlushDeclError!void {
535557 const gpa = self.base.allocator;
536558
537559 const fwd_decl = &self.lazy_fwd_decl_buf;
......@@ -546,12 +568,16 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa
546568 .is_naked_fn = false,
547569 .fwd_decl = fwd_decl.toManaged(gpa),
548570 .ctypes = ctypes.*,
571 .anon_decl_deps = .{},
549572 },
550573 .code = code.toManaged(gpa),
551574 .indent_writer = undefined, // set later so we can get a pointer to object.code
552575 };
553576 object.indent_writer = .{ .underlying_writer = object.code.writer() };
554577 defer {
578 // If this assert trips just handle the anon_decl_deps the same as
579 // `updateFunc()` does.
580 assert(object.dg.anon_decl_deps.count() == 0);
555581 object.dg.ctypes.deinit(gpa);
556582 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
557583 code.* = object.code.moveToUnmanaged();