authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-29 19:07:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 12:12:51-07:00
logc4b0b7a30bf96590f9849f64a3d86fe2ebbc6a26
treed7c32643bbdd61d5ebf1d73e7b78ddac553a3818
parent9d069d98e3e3773d76bfa4fb07cf4bcbf06e2b67

C backend: render anon decls

Introduce the new mechanism needed to render anonymous decls to C code that the frontend is now using. The current strategy is to collect the set of used anonymous decls into one ArrayHashMap for the entire compilation, and then render them during flush(). In the future this may need to be adjusted for incremental compilation purposes, so that removing a Decl from decl_table means that newly unused anonymous decls are no longer rendered. However, let's do one thing at a time. The only goal of this branch is to stop using Module.Decl objects for unnamed constants.

2 files changed, 181 insertions(+), 90 deletions(-)

src/codegen/c.zig+37-19
...@@ -530,7 +530,7 @@ pub const DeclGen = struct {...@@ -530,7 +530,7 @@ pub const DeclGen = struct {
530 ctypes: CType.Store,530 ctypes: CType.Store,
531 /// Keeps track of anonymous decls that need to be rendered before this531 /// Keeps track of anonymous decls that need to be rendered before this
532 /// (named) Decl in the output C code.532 /// (named) Decl in the output C code.
533 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),533 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
534534
535 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 } {
536 @setCold(true);536 @setCold(true);
...@@ -586,12 +586,13 @@ pub const DeclGen = struct {...@@ -586,12 +586,13 @@ pub const DeclGen = struct {
586 try dg.renderType(writer, ty);586 try dg.renderType(writer, ty);
587 try writer.writeByte(')');587 try writer.writeByte(')');
588 }588 }
589 try writer.print("&__anon_{d}", .{@intFromEnum(decl_val)});589 try writer.writeByte('&');
590 try renderAnonDeclName(writer, decl_val);
590 if (need_typecast) try writer.writeByte(')');591 if (need_typecast) try writer.writeByte(')');
591592
592 // Indicate that the anon decl should be rendered to the output so that593 // Indicate that the anon decl should be rendered to the output so that
593 // our reference above is not undefined.594 // our reference above is not undefined.
594 try dg.anon_decl_deps.put(dg.gpa, decl_val, {});595 _ = try dg.anon_decl_deps.getOrPut(dg.gpa, decl_val);
595 }596 }
596597
597 fn renderDeclValue(598 fn renderDeclValue(
...@@ -1806,7 +1807,7 @@ pub const DeclGen = struct {...@@ -1806,7 +1807,7 @@ pub const DeclGen = struct {
1806 .none => unreachable,1807 .none => unreachable,
1807 .local, .new_local => |i| return w.print("t{d}", .{i}),1808 .local, .new_local => |i| return w.print("t{d}", .{i}),
1808 .local_ref => |i| return w.print("&t{d}", .{i}),1809 .local_ref => |i| return w.print("&t{d}", .{i}),
1809 .constant => unreachable,1810 .constant => |val| return renderAnonDeclName(w, val),
1810 .arg => |i| return w.print("a{d}", .{i}),1811 .arg => |i| return w.print("a{d}", .{i}),
1811 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),1812 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
1812 .field => |i| return w.print("f{d}", .{i}),1813 .field => |i| return w.print("f{d}", .{i}),
...@@ -1924,6 +1925,10 @@ pub const DeclGen = struct {...@@ -1924,6 +1925,10 @@ pub const DeclGen = struct {
1924 }1925 }
1925 }1926 }
19261927
1928 fn renderAnonDeclName(writer: anytype, anon_decl_val: InternPool.Index) !void {
1929 return writer.print("__anon_{d}", .{@intFromEnum(anon_decl_val)});
1930 }
1931
1927 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {1932 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
1928 try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));1933 try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));
1929 }1934 }
...@@ -2761,7 +2766,6 @@ pub fn genDecl(o: *Object) !void {...@@ -2761,7 +2766,6 @@ pub fn genDecl(o: *Object) !void {
27612766
2762 const mod = o.dg.module;2767 const mod = o.dg.module;
2763 const decl_index = o.dg.decl_index.unwrap().?;2768 const decl_index = o.dg.decl_index.unwrap().?;
2764 const decl_c_value = .{ .decl = decl_index };
2765 const decl = mod.declPtr(decl_index);2769 const decl = mod.declPtr(decl_index);
2766 const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };2770 const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };
27672771
...@@ -2785,6 +2789,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2785,6 +2789,7 @@ pub fn genDecl(o: *Object) !void {
2785 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2789 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2786 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2790 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
2787 try w.print("zig_linksection(\"{s}\", ", .{s});2791 try w.print("zig_linksection(\"{s}\", ", .{s});
2792 const decl_c_value = .{ .decl = decl_index };
2788 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);2793 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);
2789 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");2794 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");
2790 try w.writeAll(" = ");2795 try w.writeAll(" = ");
...@@ -2793,22 +2798,35 @@ pub fn genDecl(o: *Object) !void {...@@ -2793,22 +2798,35 @@ pub fn genDecl(o: *Object) !void {
2793 try o.indent_writer.insertNewline();2798 try o.indent_writer.insertNewline();
2794 } else {2799 } else {
2795 const is_global = o.dg.module.decl_exports.contains(decl_index);2800 const is_global = o.dg.module.decl_exports.contains(decl_index);
2796 const fwd_decl_writer = o.dg.fwd_decl.writer();2801 const decl_c_value = .{ .decl = decl_index };
2802 return genDeclValue(o, tv, is_global, decl_c_value, decl.alignment, decl.@"linksection");
2803 }
2804}
27972805
2798 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2806pub fn genDeclValue(
2799 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete);2807 o: *Object,
2800 try fwd_decl_writer.writeAll(";\n");2808 tv: TypedValue,
2809 is_global: bool,
2810 decl_c_value: CValue,
2811 alignment: Alignment,
2812 link_section: InternPool.OptionalNullTerminatedString,
2813) !void {
2814 const fwd_decl_writer = o.dg.fwd_decl.writer();
28012815
2802 const w = o.writer();2816 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2803 if (!is_global) try w.writeAll("static ");2817 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete);
2804 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2818 try fwd_decl_writer.writeAll(";\n");
2805 try w.print("zig_linksection(\"{s}\", ", .{s});2819
2806 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete);2820 const mod = o.dg.module;
2807 if (decl.@"linksection" != .none) try w.writeAll(", read)");2821 const w = o.writer();
2808 try w.writeAll(" = ");2822 if (!is_global) try w.writeAll("static ");
2809 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2823 if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s|
2810 try w.writeAll(";\n");2824 try w.print("zig_linksection(\"{s}\", ", .{s});
2811 }2825 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, alignment, .complete);
2826 if (link_section != .none) try w.writeAll(", read)");
2827 try w.writeAll(" = ");
2828 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
2829 try w.writeAll(";\n");
2812}2830}
28132831
2814pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {2832pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
src/link/C.zig+144-71
...@@ -27,6 +27,9 @@ decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},...@@ -27,6 +27,9 @@ decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},
27/// While in progress, a separate buffer is used, and then when finished, the27/// While in progress, a separate buffer is used, and then when finished, the
28/// buffer is copied into this one.28/// buffer is copied into this one.
29string_bytes: std.ArrayListUnmanaged(u8) = .{},29string_bytes: std.ArrayListUnmanaged(u8) = .{},
30/// Tracks all the anonymous decls that are used by all the decls so they can
31/// be rendered during flush().
32anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
3033
31/// Optimization, `updateDecl` reuses this buffer rather than creating a new34/// Optimization, `updateDecl` reuses this buffer rather than creating a new
32/// one with every call.35/// one with every call.
...@@ -34,9 +37,6 @@ fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},...@@ -34,9 +37,6 @@ fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
34/// Optimization, `updateDecl` reuses this buffer rather than creating a new37/// Optimization, `updateDecl` reuses this buffer rather than creating a new
35/// one with every call.38/// one with every call.
36code_buf: std.ArrayListUnmanaged(u8) = .{},39code_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) = .{},
40/// Optimization, `flush` reuses this buffer rather than creating a new40/// Optimization, `flush` reuses this buffer rather than creating a new
41/// one with every call.41/// one with every call.
42lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},42lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
...@@ -45,7 +45,7 @@ lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},...@@ -45,7 +45,7 @@ lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
45lazy_code_buf: std.ArrayListUnmanaged(u8) = .{},45lazy_code_buf: std.ArrayListUnmanaged(u8) = .{},
4646
47/// A reference into `string_bytes`.47/// A reference into `string_bytes`.
48const String = struct {48const String = extern struct {
49 start: u32,49 start: u32,
50 len: u32,50 len: u32,
5151
...@@ -54,8 +54,9 @@ const String = struct {...@@ -54,8 +54,9 @@ const String = struct {
54 .len = 0,54 .len = 0,
55 };55 };
56};56};
57
57/// Per-declaration data.58/// Per-declaration data.
58const DeclBlock = struct {59pub const DeclBlock = struct {
59 code: String = String.empty,60 code: String = String.empty,
60 fwd_decl: String = String.empty,61 fwd_decl: String = String.empty,
61 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate62 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
...@@ -120,10 +121,14 @@ pub fn deinit(self: *C) void {...@@ -120,10 +121,14 @@ pub fn deinit(self: *C) void {
120 }121 }
121 self.decl_table.deinit(gpa);122 self.decl_table.deinit(gpa);
122123
124 for (self.anon_decls.values()) |*db| {
125 db.deinit(gpa);
126 }
127 self.anon_decls.deinit(gpa);
128
123 self.string_bytes.deinit(gpa);129 self.string_bytes.deinit(gpa);
124 self.fwd_decl_buf.deinit(gpa);130 self.fwd_decl_buf.deinit(gpa);
125 self.code_buf.deinit(gpa);131 self.code_buf.deinit(gpa);
126 self.scratch_anon_decl_deps.deinit(gpa);
127}132}
128133
129pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {134pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
...@@ -158,57 +163,110 @@ pub fn updateFunc(...@@ -158,57 +163,110 @@ pub fn updateFunc(
158 lazy_fns.clearRetainingCapacity();163 lazy_fns.clearRetainingCapacity();
159 fwd_decl.clearRetainingCapacity();164 fwd_decl.clearRetainingCapacity();
160 code.clearRetainingCapacity();165 code.clearRetainingCapacity();
161 self.scratch_anon_decl_deps.clearRetainingCapacity();
162166
163 {167 var function: codegen.Function = .{
164 var function: codegen.Function = .{168 .value_map = codegen.CValueMap.init(gpa),
165 .value_map = codegen.CValueMap.init(gpa),169 .air = air,
166 .air = air,170 .liveness = liveness,
167 .liveness = liveness,171 .func_index = func_index,
168 .func_index = func_index,172 .object = .{
169 .object = .{173 .dg = .{
170 .dg = .{174 .gpa = gpa,
171 .gpa = gpa,175 .module = module,
172 .module = module,176 .error_msg = null,
173 .error_msg = null,177 .decl_index = decl_index.toOptional(),
174 .decl_index = decl_index.toOptional(),178 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
175 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,179 .fwd_decl = fwd_decl.toManaged(gpa),
176 .fwd_decl = fwd_decl.toManaged(gpa),180 .ctypes = ctypes.*,
177 .ctypes = ctypes.*,181 .anon_decl_deps = self.anon_decls,
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
182 },182 },
183 .lazy_fns = lazy_fns.*,183 .code = code.toManaged(gpa),
184 };184 .indent_writer = undefined, // set later so we can get a pointer to object.code
185 },
186 .lazy_fns = lazy_fns.*,
187 };
185188
186 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };189 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
187 defer {190 defer {
188 self.scratch_anon_decl_deps = function.object.dg.anon_decl_deps;191 self.anon_decls = function.object.dg.anon_decl_deps;
189 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();192 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
190 code.* = function.object.code.moveToUnmanaged();193 code.* = function.object.code.moveToUnmanaged();
191 function.deinit();194 function.deinit();
192 }195 }
193196
194 codegen.genFunc(&function) catch |err| switch (err) {197 codegen.genFunc(&function) catch |err| switch (err) {
195 error.AnalysisFail => {198 error.AnalysisFail => {
196 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);199 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
197 return;200 return;
198 },201 },
199 else => |e| return e,202 else => |e| return e,
200 };203 };
204
205 ctypes.* = function.object.dg.ctypes.move();
206 lazy_fns.* = function.lazy_fns.move();
201207
202 ctypes.* = function.object.dg.ctypes.move();208 // Free excess allocated memory for this Decl.
203 lazy_fns.* = function.lazy_fns.move();209 ctypes.shrinkAndFree(gpa, ctypes.count());
210 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
211
212 gop.value_ptr.code = try self.addString(function.object.code.items);
213 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
214}
215
216fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
217 const gpa = self.base.allocator;
218 const anon_decl = self.anon_decls.keys()[i];
204219
205 // Free excess allocated memory for this Decl.220 const fwd_decl = &self.fwd_decl_buf;
206 ctypes.shrinkAndFree(gpa, ctypes.count());221 const code = &self.code_buf;
207 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());222 fwd_decl.clearRetainingCapacity();
223 code.clearRetainingCapacity();
208224
209 gop.value_ptr.code = try self.addString(function.object.code.items);225 var object: codegen.Object = .{
210 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);226 .dg = .{
227 .gpa = gpa,
228 .module = module,
229 .error_msg = null,
230 .decl_index = .none,
231 .is_naked_fn = false,
232 .fwd_decl = fwd_decl.toManaged(gpa),
233 .ctypes = .{},
234 .anon_decl_deps = self.anon_decls,
235 },
236 .code = code.toManaged(gpa),
237 .indent_writer = undefined, // set later so we can get a pointer to object.code
238 };
239 object.indent_writer = .{ .underlying_writer = object.code.writer() };
240
241 defer {
242 self.anon_decls = object.dg.anon_decl_deps;
243 object.dg.ctypes.deinit(object.dg.gpa);
244 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
245 code.* = object.code.moveToUnmanaged();
211 }246 }
247
248 const tv: @import("../TypedValue.zig") = .{
249 .ty = module.intern_pool.typeOf(anon_decl).toType(),
250 .val = anon_decl.toValue(),
251 };
252 const c_value: codegen.CValue = .{ .constant = anon_decl };
253 codegen.genDeclValue(&object, tv, false, c_value, .none, .none) catch |err| switch (err) {
254 error.AnalysisFail => {
255 @panic("TODO: C backend AnalysisFail on anonymous decl");
256 //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
257 //return;
258 },
259 else => |e| return e,
260 };
261
262 // Free excess allocated memory for this Decl.
263 object.dg.ctypes.shrinkAndFree(gpa, object.dg.ctypes.count());
264
265 object.dg.anon_decl_deps.values()[i] = .{
266 .code = try self.addString(object.code.items),
267 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
268 .ctypes = object.dg.ctypes.move(),
269 };
212}270}
213271
214pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {272pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -227,7 +285,6 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -227,7 +285,6 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
227 ctypes.clearRetainingCapacity(gpa);285 ctypes.clearRetainingCapacity(gpa);
228 fwd_decl.clearRetainingCapacity();286 fwd_decl.clearRetainingCapacity();
229 code.clearRetainingCapacity();287 code.clearRetainingCapacity();
230 self.scratch_anon_decl_deps.clearRetainingCapacity();
231288
232 var object: codegen.Object = .{289 var object: codegen.Object = .{
233 .dg = .{290 .dg = .{
...@@ -238,14 +295,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -238,14 +295,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
238 .is_naked_fn = false,295 .is_naked_fn = false,
239 .fwd_decl = fwd_decl.toManaged(gpa),296 .fwd_decl = fwd_decl.toManaged(gpa),
240 .ctypes = ctypes.*,297 .ctypes = ctypes.*,
241 .anon_decl_deps = self.scratch_anon_decl_deps,298 .anon_decl_deps = self.anon_decls,
242 },299 },
243 .code = code.toManaged(gpa),300 .code = code.toManaged(gpa),
244 .indent_writer = undefined, // set later so we can get a pointer to object.code301 .indent_writer = undefined, // set later so we can get a pointer to object.code
245 };302 };
246 object.indent_writer = .{ .underlying_writer = object.code.writer() };303 object.indent_writer = .{ .underlying_writer = object.code.writer() };
247 defer {304 defer {
248 self.scratch_anon_decl_deps = object.dg.anon_decl_deps;305 self.anon_decls = object.dg.anon_decl_deps;
249 object.dg.ctypes.deinit(object.dg.gpa);306 object.dg.ctypes.deinit(object.dg.gpa);
250 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();307 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
251 code.* = object.code.moveToUnmanaged();308 code.* = object.code.moveToUnmanaged();
...@@ -303,6 +360,13 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -303,6 +360,13 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
303 const gpa = self.base.allocator;360 const gpa = self.base.allocator;
304 const module = self.base.options.module.?;361 const module = self.base.options.module.?;
305362
363 {
364 var i: usize = 0;
365 while (i < self.anon_decls.count()) : (i += 1) {
366 try updateAnonDecl(self, module, i);
367 }
368 }
369
306 // This code path happens exclusively with -ofmt=c. The flush logic for370 // This code path happens exclusively with -ofmt=c. The flush logic for
307 // emit-h is in `flushEmitH` below.371 // emit-h is in `flushEmitH` below.
308372
...@@ -345,10 +409,15 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -345,10 +409,15 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
345 for (module.decl_exports.values()) |exports| for (exports.items) |@"export"|409 for (module.decl_exports.values()) |exports| for (exports.items) |@"export"|
346 try export_names.put(gpa, @"export".opts.name, {});410 try export_names.put(gpa, @"export".opts.name, {});
347411
348 const decl_keys = self.decl_table.keys();412 for (self.anon_decls.values()) |*decl_block| {
349 for (decl_keys) |decl_index| {413 try self.flushDeclBlock(&f, decl_block, export_names, .none);
414 }
415
416 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, *decl_block| {
350 assert(module.declPtr(decl_index).has_tv);417 assert(module.declPtr(decl_index).has_tv);
351 try self.flushDecl(&f, decl_index, export_names);418 const decl = module.declPtr(decl_index);
419 const extern_symbol_name = if (decl.isExtern(module)) decl.name.toOptional() else .none;
420 try self.flushDeclBlock(&f, decl_block, export_names, extern_symbol_name);
352 }421 }
353 }422 }
354423
...@@ -358,8 +427,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -358,8 +427,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
358 assert(f.ctypes.count() == 0);427 assert(f.ctypes.count() == 0);
359 try self.flushCTypes(&f, .none, f.lazy_ctypes);428 try self.flushCTypes(&f, .none, f.lazy_ctypes);
360429
361 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, db| {430 for (self.anon_decls.values()) |decl_block| {
362 try self.flushCTypes(&f, decl_index.toOptional(), db.ctypes);431 try self.flushCTypes(&f, .none, decl_block.ctypes);
432 }
433
434 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {
435 try self.flushCTypes(&f, decl_index.toOptional(), decl_block.ctypes);
363 }436 }
364 }437 }
365438
...@@ -377,10 +450,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -377,10 +450,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
377 f.file_size += lazy_fwd_decl_len;450 f.file_size += lazy_fwd_decl_len;
378451
379 // Now the code.452 // Now the code.
453 const anon_decl_values = self.anon_decls.values();
380 const decl_values = self.decl_table.values();454 const decl_values = self.decl_table.values();
381 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);455 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + anon_decl_values.len + decl_values.len);
382 f.appendBufAssumeCapacity(self.lazy_code_buf.items);456 f.appendBufAssumeCapacity(self.lazy_code_buf.items);
383 for (decl_values) |decl| f.appendBufAssumeCapacity(self.getString(decl.code));457 for (anon_decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
458 for (decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
384459
385 const file = self.base.file.?;460 const file = self.base.file.?;
386 try file.setEndPos(f.file_size);461 try file.setEndPos(f.file_size);
...@@ -526,16 +601,14 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {...@@ -526,16 +601,14 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
526 .is_naked_fn = false,601 .is_naked_fn = false,
527 .fwd_decl = fwd_decl.toManaged(gpa),602 .fwd_decl = fwd_decl.toManaged(gpa),
528 .ctypes = ctypes.*,603 .ctypes = ctypes.*,
529 .anon_decl_deps = .{},604 .anon_decl_deps = self.anon_decls,
530 },605 },
531 .code = code.toManaged(gpa),606 .code = code.toManaged(gpa),
532 .indent_writer = undefined, // set later so we can get a pointer to object.code607 .indent_writer = undefined, // set later so we can get a pointer to object.code
533 };608 };
534 object.indent_writer = .{ .underlying_writer = object.code.writer() };609 object.indent_writer = .{ .underlying_writer = object.code.writer() };
535 defer {610 defer {
536 // If this assert trips just handle the anon_decl_deps the same as611 self.anon_decls = object.dg.anon_decl_deps;
537 // `updateFunc()` does.
538 assert(object.dg.anon_decl_deps.count() == 0);
539 object.dg.ctypes.deinit(gpa);612 object.dg.ctypes.deinit(gpa);
540 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();613 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
541 code.* = object.code.moveToUnmanaged();614 code.* = object.code.moveToUnmanaged();
...@@ -604,22 +677,22 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError...@@ -604,22 +677,22 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError
604 }677 }
605}678}
606679
607fn flushDecl(680fn flushDeclBlock(
608 self: *C,681 self: *C,
609 f: *Flush,682 f: *Flush,
610 decl_index: Module.Decl.Index,683 decl_block: *DeclBlock,
611 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),684 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
685 extern_symbol_name: InternPool.OptionalNullTerminatedString,
612) FlushDeclError!void {686) FlushDeclError!void {
613 const gpa = self.base.allocator;687 const gpa = self.base.allocator;
614 const mod = self.base.options.module.?;
615 const decl = mod.declPtr(decl_index);
616
617 const decl_block = self.decl_table.getPtr(decl_index).?;
618
619 try self.flushLazyFns(f, decl_block.lazy_fns);688 try self.flushLazyFns(f, decl_block.lazy_fns);
620 try f.all_buffers.ensureUnusedCapacity(gpa, 1);689 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
621 if (!(decl.isExtern(mod) and export_names.contains(decl.name)))690 fwd_decl: {
691 if (extern_symbol_name.unwrap()) |name| {
692 if (export_names.contains(name)) break :fwd_decl;
693 }
622 f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));694 f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));
695 }
623}696}
624697
625pub fn flushEmitH(module: *Module) !void {698pub fn flushEmitH(module: *Module) !void {