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...@@ -3499,6 +3499,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3499 .is_naked_fn = false,3499 .is_naked_fn = false,
3500 .fwd_decl = fwd_decl.toManaged(gpa),3500 .fwd_decl = fwd_decl.toManaged(gpa),
3501 .ctypes = .{},3501 .ctypes = .{},
3502 .anon_decl_deps = .{},
3502 };3503 };
3503 defer {3504 defer {
3504 dg.ctypes.deinit(gpa);3505 dg.ctypes.deinit(gpa);
src/codegen/c.zig+60-24
...@@ -528,6 +528,9 @@ pub const DeclGen = struct {...@@ -528,6 +528,9 @@ pub const DeclGen = struct {
528 fwd_decl: std.ArrayList(u8),528 fwd_decl: std.ArrayList(u8),
529 error_msg: ?*Module.ErrorMsg,529 error_msg: ?*Module.ErrorMsg,
530 ctypes: CType.Store,530 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
532 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {535 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
533 @setCold(true);536 @setCold(true);
...@@ -540,6 +543,57 @@ pub const DeclGen = struct {...@@ -540,6 +543,57 @@ pub const DeclGen = struct {
540 return error.AnalysisFail;543 return error.AnalysisFail;
541 }544 }
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
543 fn renderDeclValue(597 fn renderDeclValue(
544 dg: *DeclGen,598 dg: *DeclGen,
545 writer: anytype,599 writer: anytype,
...@@ -593,18 +647,9 @@ pub const DeclGen = struct {...@@ -593,18 +647,9 @@ pub const DeclGen = struct {
593 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);647 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);
594 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;648 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;
595 switch (ptr.addr) {649 switch (ptr.addr) {
596 .decl, .mut_decl => try dg.renderDeclValue(650 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location),
597 writer,651 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location),
598 ptr_ty,652 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location),
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"),
608 .int => |int| {653 .int => |int| {
609 try writer.writeByte('(');654 try writer.writeByte('(');
610 try dg.renderCType(writer, ptr_cty);655 try dg.renderCType(writer, ptr_cty);
...@@ -1145,18 +1190,9 @@ pub const DeclGen = struct {...@@ -1145,18 +1190,9 @@ pub const DeclGen = struct {
1145 else => val.slicePtr(mod),1190 else => val.slicePtr(mod),
1146 };1191 };
1147 switch (ptr.addr) {1192 switch (ptr.addr) {
1148 .decl, .mut_decl => try dg.renderDeclValue(1193 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location),
1149 writer,1194 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location),
1150 ptr_ty,1195 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location),
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"),
1160 .int => |int| {1196 .int => |int| {
1161 try writer.writeAll("((");1197 try writer.writeAll("((");
1162 try dg.renderType(writer, ptr_ty);1198 try dg.renderType(writer, ptr_ty);
src/link/C.zig+72-46
...@@ -34,6 +34,9 @@ fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},...@@ -34,6 +34,9 @@ fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
34/// Optimization, `updateDecl` reuses this buffer rather than creating a new34/// Optimization, `updateDecl` reuses this buffer rather than creating a new
35/// one with every call.35/// one with every call.
36code_buf: std.ArrayListUnmanaged(u8) = .{},36code_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) = .{},
37/// Optimization, `flush` reuses this buffer rather than creating a new40/// Optimization, `flush` reuses this buffer rather than creating a new
38/// one with every call.41/// one with every call.
39lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},42lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
...@@ -51,7 +54,6 @@ const String = struct {...@@ -51,7 +54,6 @@ const String = struct {
51 .len = 0,54 .len = 0,
52 };55 };
53};56};
54
55/// Per-declaration data.57/// Per-declaration data.
56const DeclBlock = struct {58const DeclBlock = struct {
57 code: String = String.empty,59 code: String = String.empty,
...@@ -98,7 +100,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C...@@ -98,7 +100,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
98 var c_file = try gpa.create(C);100 var c_file = try gpa.create(C);
99 errdefer gpa.destroy(c_file);101 errdefer gpa.destroy(c_file);
100102
101 c_file.* = C{103 c_file.* = .{
102 .base = .{104 .base = .{
103 .tag = .c,105 .tag = .c,
104 .options = options,106 .options = options,
...@@ -121,6 +123,7 @@ pub fn deinit(self: *C) void {...@@ -121,6 +123,7 @@ pub fn deinit(self: *C) void {
121 self.string_bytes.deinit(gpa);123 self.string_bytes.deinit(gpa);
122 self.fwd_decl_buf.deinit(gpa);124 self.fwd_decl_buf.deinit(gpa);
123 self.code_buf.deinit(gpa);125 self.code_buf.deinit(gpa);
126 self.scratch_anon_decl_deps.deinit(gpa);
124}127}
125128
126pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {129pub 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 {...@@ -131,10 +134,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
131 }134 }
132}135}
133136
134pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {137pub fn updateFunc(
135 const tracy = trace(@src());138 self: *C,
136 defer tracy.end();139 module: *Module,
137140 func_index: InternPool.Index,
141 air: Air,
142 liveness: Liveness,
143) !void {
138 const gpa = self.base.allocator;144 const gpa = self.base.allocator;
139145
140 const func = module.funcInfo(func_index);146 const func = module.funcInfo(func_index);
...@@ -152,52 +158,57 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:...@@ -152,52 +158,57 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
152 lazy_fns.clearRetainingCapacity();158 lazy_fns.clearRetainingCapacity();
153 fwd_decl.clearRetainingCapacity();159 fwd_decl.clearRetainingCapacity();
154 code.clearRetainingCapacity();160 code.clearRetainingCapacity();
161 self.scratch_anon_decl_deps.clearRetainingCapacity();
155162
156 var function: codegen.Function = .{163 {
157 .value_map = codegen.CValueMap.init(gpa),164 var function: codegen.Function = .{
158 .air = air,165 .value_map = codegen.CValueMap.init(gpa),
159 .liveness = liveness,166 .air = air,
160 .func_index = func_index,167 .liveness = liveness,
161 .object = .{168 .func_index = func_index,
162 .dg = .{169 .object = .{
163 .gpa = gpa,170 .dg = .{
164 .module = module,171 .gpa = gpa,
165 .error_msg = null,172 .module = module,
166 .decl_index = decl_index.toOptional(),173 .error_msg = null,
167 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,174 .decl_index = decl_index.toOptional(),
168 .fwd_decl = fwd_decl.toManaged(gpa),175 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
169 .ctypes = ctypes.*,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
170 },182 },
171 .code = code.toManaged(gpa),183 .lazy_fns = lazy_fns.*,
172 .indent_writer = undefined, // set later so we can get a pointer to object.code184 };
173 },
174 .lazy_fns = lazy_fns.*,
175 };
176185
177 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };186 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
178 defer {187 defer {
179 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();188 self.scratch_anon_decl_deps = function.object.dg.anon_decl_deps;
180 code.* = function.object.code.moveToUnmanaged();189 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
181 function.deinit();190 code.* = function.object.code.moveToUnmanaged();
182 }191 function.deinit();
192 }
183193
184 codegen.genFunc(&function) catch |err| switch (err) {194 codegen.genFunc(&function) catch |err| switch (err) {
185 error.AnalysisFail => {195 error.AnalysisFail => {
186 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);196 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
187 return;197 return;
188 },198 },
189 else => |e| return e,199 else => |e| return e,
190 };200 };
191201
192 ctypes.* = function.object.dg.ctypes.move();202 ctypes.* = function.object.dg.ctypes.move();
193 lazy_fns.* = function.lazy_fns.move();203 lazy_fns.* = function.lazy_fns.move();
194204
195 // Free excess allocated memory for this Decl.205 // Free excess allocated memory for this Decl.
196 ctypes.shrinkAndFree(gpa, ctypes.count());206 ctypes.shrinkAndFree(gpa, ctypes.count());
197 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());207 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
198208
199 gop.value_ptr.code = try self.addString(function.object.code.items);209 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);210 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
211 }
201}212}
202213
203pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {214pub 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...@@ -216,6 +227,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
216 ctypes.clearRetainingCapacity(gpa);227 ctypes.clearRetainingCapacity(gpa);
217 fwd_decl.clearRetainingCapacity();228 fwd_decl.clearRetainingCapacity();
218 code.clearRetainingCapacity();229 code.clearRetainingCapacity();
230 self.scratch_anon_decl_deps.clearRetainingCapacity();
219231
220 var object: codegen.Object = .{232 var object: codegen.Object = .{
221 .dg = .{233 .dg = .{
...@@ -226,12 +238,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -226,12 +238,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
226 .is_naked_fn = false,238 .is_naked_fn = false,
227 .fwd_decl = fwd_decl.toManaged(gpa),239 .fwd_decl = fwd_decl.toManaged(gpa),
228 .ctypes = ctypes.*,240 .ctypes = ctypes.*,
241 .anon_decl_deps = self.scratch_anon_decl_deps,
229 },242 },
230 .code = code.toManaged(gpa),243 .code = code.toManaged(gpa),
231 .indent_writer = undefined, // set later so we can get a pointer to object.code244 .indent_writer = undefined, // set later so we can get a pointer to object.code
232 };245 };
233 object.indent_writer = .{ .underlying_writer = object.code.writer() };246 object.indent_writer = .{ .underlying_writer = object.code.writer() };
234 defer {247 defer {
248 self.scratch_anon_decl_deps = object.dg.anon_decl_deps;
235 object.dg.ctypes.deinit(object.dg.gpa);249 object.dg.ctypes.deinit(object.dg.gpa);
236 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();250 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
237 code.* = object.code.moveToUnmanaged();251 code.* = object.code.moveToUnmanaged();
...@@ -512,12 +526,16 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {...@@ -512,12 +526,16 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
512 .is_naked_fn = false,526 .is_naked_fn = false,
513 .fwd_decl = fwd_decl.toManaged(gpa),527 .fwd_decl = fwd_decl.toManaged(gpa),
514 .ctypes = ctypes.*,528 .ctypes = ctypes.*,
529 .anon_decl_deps = .{},
515 },530 },
516 .code = code.toManaged(gpa),531 .code = code.toManaged(gpa),
517 .indent_writer = undefined, // set later so we can get a pointer to object.code532 .indent_writer = undefined, // set later so we can get a pointer to object.code
518 };533 };
519 object.indent_writer = .{ .underlying_writer = object.code.writer() };534 object.indent_writer = .{ .underlying_writer = object.code.writer() };
520 defer {535 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);
521 object.dg.ctypes.deinit(gpa);539 object.dg.ctypes.deinit(gpa);
522 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();540 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
523 code.* = object.code.moveToUnmanaged();541 code.* = object.code.moveToUnmanaged();
...@@ -531,7 +549,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {...@@ -531,7 +549,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
531 ctypes.* = object.dg.ctypes.move();549 ctypes.* = object.dg.ctypes.move();
532}550}
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 {
535 const gpa = self.base.allocator;557 const gpa = self.base.allocator;
536558
537 const fwd_decl = &self.lazy_fwd_decl_buf;559 const fwd_decl = &self.lazy_fwd_decl_buf;
...@@ -546,12 +568,16 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa...@@ -546,12 +568,16 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa
546 .is_naked_fn = false,568 .is_naked_fn = false,
547 .fwd_decl = fwd_decl.toManaged(gpa),569 .fwd_decl = fwd_decl.toManaged(gpa),
548 .ctypes = ctypes.*,570 .ctypes = ctypes.*,
571 .anon_decl_deps = .{},
549 },572 },
550 .code = code.toManaged(gpa),573 .code = code.toManaged(gpa),
551 .indent_writer = undefined, // set later so we can get a pointer to object.code574 .indent_writer = undefined, // set later so we can get a pointer to object.code
552 };575 };
553 object.indent_writer = .{ .underlying_writer = object.code.writer() };576 object.indent_writer = .{ .underlying_writer = object.code.writer() };
554 defer {577 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);
555 object.dg.ctypes.deinit(gpa);581 object.dg.ctypes.deinit(gpa);
556 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();582 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
557 code.* = object.code.moveToUnmanaged();583 code.* = object.code.moveToUnmanaged();