authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-06-24 12:23:12-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-02 16:25:47-07:00
log725dbf295e82624477aa4d95ba71ec02d9c94978
treea2bb810001f0e413cf59bf44aaa8995c58648296
parent69fd07bd50932405110584c32f6614fa1e247e1c

cbe: reapply writer changes


2 files changed, 400 insertions(+), 372 deletions(-)

src/codegen/c.zig+225-214
......@@ -56,6 +56,7 @@ pub const Mir = struct {
5656 /// less than the natural alignment.
5757 uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
5858 // These remaining fields are essentially just an owned version of `link.C.AvBlock`.
59 code_header: []u8,
5960 code: []u8,
6061 fwd_decl: []u8,
6162 ctype_pool: CType.Pool,
......@@ -63,6 +64,7 @@ pub const Mir = struct {
6364
6465 pub fn deinit(mir: *Mir, gpa: Allocator) void {
6566 mir.uavs.deinit(gpa);
67 gpa.free(mir.code_header);
6668 gpa.free(mir.code);
6769 gpa.free(mir.fwd_decl);
6870 mir.ctype_pool.deinit(gpa);
......@@ -345,23 +347,23 @@ fn isReservedIdent(ident: []const u8) bool {
345347
346348fn formatIdent(
347349 ident: []const u8,
348 writer: *Writer,
350 w: *Writer,
349351 comptime fmt_str: []const u8,
350352) Writer.Error!void {
351353 const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
352354 if (solo and isReservedIdent(ident)) {
353 try writer.writeAll("zig_e_");
355 try w.writeAll("zig_e_");
354356 }
355357 for (ident, 0..) |c, i| {
356358 switch (c) {
357 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
358 '.' => try writer.writeByte('_'),
359 'a'...'z', 'A'...'Z', '_' => try w.writeByte(c),
360 '.' => try w.writeByte('_'),
359361 '0'...'9' => if (i == 0) {
360 try writer.print("_{x:2}", .{c});
362 try w.print("_{x:2}", .{c});
361363 } else {
362 try writer.writeByte(c);
364 try w.writeByte(c);
363365 },
364 else => try writer.print("_{x:2}", .{c}),
366 else => try w.print("_{x:2}", .{c}),
365367 }
366368 }
367369}
......@@ -375,13 +377,13 @@ const CTypePoolStringFormatData = struct {
375377};
376378fn formatCTypePoolString(
377379 data: CTypePoolStringFormatData,
378 writer: *Writer,
380 w: *Writer,
379381 comptime fmt_str: []const u8,
380382) Writer.Error!void {
381383 if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
382 try formatIdent(slice, writer, fmt_str)
384 try formatIdent(slice, w, fmt_str)
383385 else
384 try writer.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
386 try w.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
385387}
386388pub fn fmtCTypePoolString(
387389 ctype_pool_string: CType.Pool.String,
......@@ -441,18 +443,18 @@ pub const Function = struct {
441443 const ty = f.typeOf(ref);
442444
443445 const result: CValue = if (lowersToArray(ty, pt)) result: {
444 const writer = &f.object.code_header.buffered_writer;
446 const ch = &f.object.code_header.buffered_writer;
445447 const decl_c_value = try f.allocLocalValue(.{
446448 .ctype = try f.ctypeFromType(ty, .complete),
447449 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
448450 });
449451 const gpa = f.object.dg.gpa;
450452 try f.allocs.put(gpa, decl_c_value.new_local, false);
451 try writer.writeAll("static ");
452 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);
453 try writer.writeAll(" = ");
454 try f.object.dg.renderValue(writer, val, .StaticInitializer);
455 try writer.writeAll(";\n ");
453 try ch.writeAll("static ");
454 try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete);
455 try ch.writeAll(" = ");
456 try f.object.dg.renderValue(ch, val, .StaticInitializer);
457 try ch.writeAll(";\n ");
456458 break :result .{ .local = decl_c_value.new_local };
457459 } else .{ .constant = val };
458460
......@@ -979,7 +981,7 @@ pub const DeclGen = struct {
979981
980982 fn renderValue(
981983 dg: *DeclGen,
982 writer: *Writer,
984 w: *Writer,
983985 val: Value,
984986 location: ValueRenderLocation,
985987 ) Error!void {
......@@ -995,7 +997,7 @@ pub const DeclGen = struct {
995997 };
996998
997999 const ty = val.typeOf(zcu);
998 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);
1000 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(w, ty, location);
9991001 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
10001002 switch (ip.indexToKey(val.toIntern())) {
10011003 // types, not values
......@@ -1028,8 +1030,8 @@ pub const DeclGen = struct {
10281030 .empty_tuple => unreachable,
10291031 .@"unreachable" => unreachable,
10301032
1031 .false => try writer.writeAll("false"),
1032 .true => try writer.writeAll("true"),
1033 .false => try w.writeAll("false"),
1034 .true => try w.writeAll("true"),
10331035 },
10341036 .variable,
10351037 .@"extern",
......@@ -1038,45 +1040,45 @@ pub const DeclGen = struct {
10381040 .empty_enum_value,
10391041 => unreachable, // non-runtime values
10401042 .int => |int| switch (int.storage) {
1041 .u64, .i64, .big_int => try writer.print("{f}", .{try dg.fmtIntLiteral(val, location)}),
1043 .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteral(val, location)}),
10421044 .lazy_align, .lazy_size => {
1043 try writer.writeAll("((");
1044 try dg.renderCType(writer, ctype);
1045 try writer.print("){fx})", .{try dg.fmtIntLiteral(
1045 try w.writeAll("((");
1046 try dg.renderCType(w, ctype);
1047 try w.print("){fx})", .{try dg.fmtIntLiteral(
10461048 try pt.intValue(.usize, val.toUnsignedInt(zcu)),
10471049 .Other,
10481050 )});
10491051 },
10501052 },
1051 .err => |err| try dg.renderErrorName(writer, err.name),
1053 .err => |err| try dg.renderErrorName(w, err.name),
10521054 .error_union => |error_union| switch (ctype.info(ctype_pool)) {
10531055 .basic => switch (error_union.val) {
1054 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
1055 .payload => try writer.writeByte('0'),
1056 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1057 .payload => try w.writeByte('0'),
10561058 },
10571059 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
10581060 .aggregate => |aggregate| {
10591061 if (!location.isInitializer()) {
1060 try writer.writeByte('(');
1061 try dg.renderCType(writer, ctype);
1062 try writer.writeByte(')');
1062 try w.writeByte('(');
1063 try dg.renderCType(w, ctype);
1064 try w.writeByte(')');
10631065 }
1064 try writer.writeByte('{');
1066 try w.writeByte('{');
10651067 for (0..aggregate.fields.len) |field_index| {
1066 if (field_index > 0) try writer.writeByte(',');
1068 if (field_index > 0) try w.writeByte(',');
10671069 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
10681070 .@"error" => switch (error_union.val) {
1069 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
1070 .payload => try writer.writeByte('0'),
1071 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1072 .payload => try w.writeByte('0'),
10711073 },
10721074 .payload => switch (error_union.val) {
10731075 .err_name => try dg.renderUndefValue(
1074 writer,
1076 w,
10751077 ty.errorUnionPayload(zcu),
10761078 initializer_type,
10771079 ),
10781080 .payload => |payload| try dg.renderValue(
1079 writer,
1081 w,
10801082 Value.fromInterned(payload),
10811083 initializer_type,
10821084 ),
......@@ -1084,10 +1086,10 @@ pub const DeclGen = struct {
10841086 else => unreachable,
10851087 }
10861088 }
1087 try writer.writeByte('}');
1089 try w.writeByte('}');
10881090 },
10891091 },
1090 .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location),
1092 .enum_tag => |enum_tag| try dg.renderValue(w, Value.fromInterned(enum_tag.int), location),
10911093 .float => {
10921094 const bits = ty.floatBits(target);
10931095 const f128_val = val.toFloat(f128, zcu);
......@@ -1114,18 +1116,18 @@ pub const DeclGen = struct {
11141116
11151117 var empty = true;
11161118 if (std.math.isFinite(f128_val)) {
1117 try writer.writeAll("zig_make_");
1118 try dg.renderTypeForBuiltinFnName(writer, ty);
1119 try writer.writeByte('(');
1119 try w.writeAll("zig_make_");
1120 try dg.renderTypeForBuiltinFnName(w, ty);
1121 try w.writeByte('(');
11201122 switch (bits) {
1121 16 => try writer.print("{x}", .{val.toFloat(f16, zcu)}),
1122 32 => try writer.print("{x}", .{val.toFloat(f32, zcu)}),
1123 64 => try writer.print("{x}", .{val.toFloat(f64, zcu)}),
1124 80 => try writer.print("{x}", .{val.toFloat(f80, zcu)}),
1125 128 => try writer.print("{x}", .{f128_val}),
1123 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}),
1124 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}),
1125 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}),
1126 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}),
1127 128 => try w.print("{x}", .{f128_val}),
11261128 else => unreachable,
11271129 }
1128 try writer.writeAll(", ");
1130 try w.writeAll(", ");
11291131 empty = false;
11301132 } else {
11311133 // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan
......@@ -1149,45 +1151,45 @@ pub const DeclGen = struct {
11491151 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});
11501152 }
11511153
1152 try writer.writeAll("zig_");
1153 try writer.writeAll(if (location == .StaticInitializer) "init" else "make");
1154 try writer.writeAll("_special_");
1155 try dg.renderTypeForBuiltinFnName(writer, ty);
1156 try writer.writeByte('(');
1157 if (std.math.signbit(f128_val)) try writer.writeByte('-');
1158 try writer.writeAll(", ");
1159 try writer.writeAll(operation);
1160 try writer.writeAll(", ");
1154 try w.writeAll("zig_");
1155 try w.writeAll(if (location == .StaticInitializer) "init" else "make");
1156 try w.writeAll("_special_");
1157 try dg.renderTypeForBuiltinFnName(w, ty);
1158 try w.writeByte('(');
1159 if (std.math.signbit(f128_val)) try w.writeByte('-');
1160 try w.writeAll(", ");
1161 try w.writeAll(operation);
1162 try w.writeAll(", ");
11611163 if (std.math.isNan(f128_val)) switch (bits) {
11621164 // We only actually need to pass the significand, but it will get
11631165 // properly masked anyway, so just pass the whole value.
1164 16 => try writer.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
1165 32 => try writer.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
1166 64 => try writer.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
1167 80 => try writer.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
1168 128 => try writer.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
1166 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
1167 32 => try w.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
1168 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
1169 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
1170 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
11691171 else => unreachable,
11701172 };
1171 try writer.writeAll(", ");
1173 try w.writeAll(", ");
11721174 empty = false;
11731175 }
1174 try writer.print("{fx}", .{try dg.fmtIntLiteral(
1176 try w.print("{fx}", .{try dg.fmtIntLiteral(
11751177 try pt.intValue_big(repr_ty, repr_val_big.toConst()),
11761178 location,
11771179 )});
1178 if (!empty) try writer.writeByte(')');
1180 if (!empty) try w.writeByte(')');
11791181 },
11801182 .slice => |slice| {
11811183 const aggregate = ctype.info(ctype_pool).aggregate;
11821184 if (!location.isInitializer()) {
1183 try writer.writeByte('(');
1184 try dg.renderCType(writer, ctype);
1185 try writer.writeByte(')');
1185 try w.writeByte('(');
1186 try dg.renderCType(w, ctype);
1187 try w.writeByte(')');
11861188 }
1187 try writer.writeByte('{');
1189 try w.writeByte('{');
11881190 for (0..aggregate.fields.len) |field_index| {
1189 if (field_index > 0) try writer.writeByte(',');
1190 try dg.renderValue(writer, Value.fromInterned(
1191 if (field_index > 0) try w.writeByte(',');
1192 try dg.renderValue(w, Value.fromInterned(
11911193 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
11921194 .ptr => slice.ptr,
11931195 .len => slice.len,
......@@ -1195,33 +1197,33 @@ pub const DeclGen = struct {
11951197 },
11961198 ), initializer_type);
11971199 }
1198 try writer.writeByte('}');
1200 try w.writeByte('}');
11991201 },
12001202 .ptr => {
12011203 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
12021204 defer arena.deinit();
12031205 const derivation = try val.pointerDerivation(arena.allocator(), pt);
1204 try dg.renderPointer(writer, derivation, location);
1206 try dg.renderPointer(w, derivation, location);
12051207 },
12061208 .opt => |opt| switch (ctype.info(ctype_pool)) {
1207 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
1209 .basic => if (ctype.isBool()) try w.writeAll(switch (opt.val) {
12081210 .none => "true",
12091211 else => "false",
12101212 }) else switch (opt.val) {
1211 .none => try writer.writeByte('0'),
1213 .none => try w.writeByte('0'),
12121214 else => |payload| switch (ip.indexToKey(payload)) {
12131215 .undef => |err_ty| try dg.renderUndefValue(
1214 writer,
1216 w,
12151217 .fromInterned(err_ty),
12161218 location,
12171219 ),
1218 .err => |err| try dg.renderErrorName(writer, err.name),
1220 .err => |err| try dg.renderErrorName(w, err.name),
12191221 else => unreachable,
12201222 },
12211223 },
12221224 .pointer => switch (opt.val) {
1223 .none => try writer.writeAll("NULL"),
1224 else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),
1225 .none => try w.writeAll("NULL"),
1226 else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location),
12251227 },
12261228 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
12271229 .aggregate => |aggregate| {
......@@ -1230,7 +1232,7 @@ pub const DeclGen = struct {
12301232 else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
12311233 .is_null, .payload => {},
12321234 .ptr, .len => return dg.renderValue(
1233 writer,
1235 w,
12341236 Value.fromInterned(payload),
12351237 location,
12361238 ),
......@@ -1238,48 +1240,48 @@ pub const DeclGen = struct {
12381240 },
12391241 }
12401242 if (!location.isInitializer()) {
1241 try writer.writeByte('(');
1242 try dg.renderCType(writer, ctype);
1243 try writer.writeByte(')');
1243 try w.writeByte('(');
1244 try dg.renderCType(w, ctype);
1245 try w.writeByte(')');
12441246 }
1245 try writer.writeByte('{');
1247 try w.writeByte('{');
12461248 for (0..aggregate.fields.len) |field_index| {
1247 if (field_index > 0) try writer.writeByte(',');
1249 if (field_index > 0) try w.writeByte(',');
12481250 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1249 .is_null => try writer.writeAll(switch (opt.val) {
1251 .is_null => try w.writeAll(switch (opt.val) {
12501252 .none => "true",
12511253 else => "false",
12521254 }),
12531255 .payload => switch (opt.val) {
12541256 .none => try dg.renderUndefValue(
1255 writer,
1257 w,
12561258 ty.optionalChild(zcu),
12571259 initializer_type,
12581260 ),
12591261 else => |payload| try dg.renderValue(
1260 writer,
1262 w,
12611263 Value.fromInterned(payload),
12621264 initializer_type,
12631265 ),
12641266 },
1265 .ptr => try writer.writeAll("NULL"),
1266 .len => try dg.renderUndefValue(writer, .usize, initializer_type),
1267 .ptr => try w.writeAll("NULL"),
1268 .len => try dg.renderUndefValue(w, .usize, initializer_type),
12671269 else => unreachable,
12681270 }
12691271 }
1270 try writer.writeByte('}');
1272 try w.writeByte('}');
12711273 },
12721274 },
12731275 .aggregate => switch (ip.indexToKey(ty.toIntern())) {
12741276 .array_type, .vector_type => {
12751277 if (location == .FunctionArgument) {
1276 try writer.writeByte('(');
1277 try dg.renderCType(writer, ctype);
1278 try writer.writeByte(')');
1278 try w.writeByte('(');
1279 try dg.renderCType(w, ctype);
1280 try w.writeByte(')');
12791281 }
12801282 const ai = ty.arrayInfo(zcu);
12811283 if (ai.elem_type.eql(.u8, zcu)) {
1282 var literal: StringLiteral = .init(writer, ty.arrayLenIncludingSentinel(zcu));
1284 var literal: StringLiteral = .init(w, ty.arrayLenIncludingSentinel(zcu));
12831285 try literal.start();
12841286 var index: usize = 0;
12851287 while (index < ai.len) : (index += 1) {
......@@ -1296,28 +1298,28 @@ pub const DeclGen = struct {
12961298 }
12971299 try literal.end();
12981300 } else {
1299 try writer.writeByte('{');
1301 try w.writeByte('{');
13001302 var index: usize = 0;
13011303 while (index < ai.len) : (index += 1) {
1302 if (index != 0) try writer.writeByte(',');
1304 if (index != 0) try w.writeByte(',');
13031305 const elem_val = try val.elemValue(pt, index);
1304 try dg.renderValue(writer, elem_val, initializer_type);
1306 try dg.renderValue(w, elem_val, initializer_type);
13051307 }
13061308 if (ai.sentinel) |s| {
1307 if (index != 0) try writer.writeByte(',');
1308 try dg.renderValue(writer, s, initializer_type);
1309 if (index != 0) try w.writeByte(',');
1310 try dg.renderValue(w, s, initializer_type);
13091311 }
1310 try writer.writeByte('}');
1312 try w.writeByte('}');
13111313 }
13121314 },
13131315 .tuple_type => |tuple| {
13141316 if (!location.isInitializer()) {
1315 try writer.writeByte('(');
1316 try dg.renderCType(writer, ctype);
1317 try writer.writeByte(')');
1317 try w.writeByte('(');
1318 try dg.renderCType(w, ctype);
1319 try w.writeByte(')');
13181320 }
13191321
1320 try writer.writeByte('{');
1322 try w.writeByte('{');
13211323 var empty = true;
13221324 for (0..tuple.types.len) |field_index| {
13231325 const comptime_val = tuple.values.get(ip)[field_index];
......@@ -1325,7 +1327,7 @@ pub const DeclGen = struct {
13251327 const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);
13261328 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13271329
1328 if (!empty) try writer.writeByte(',');
1330 if (!empty) try w.writeByte(',');
13291331
13301332 const field_val = Value.fromInterned(
13311333 switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
......@@ -1337,30 +1339,30 @@ pub const DeclGen = struct {
13371339 .repeated_elem => |elem| elem,
13381340 },
13391341 );
1340 try dg.renderValue(writer, field_val, initializer_type);
1342 try dg.renderValue(w, field_val, initializer_type);
13411343
13421344 empty = false;
13431345 }
1344 try writer.writeByte('}');
1346 try w.writeByte('}');
13451347 },
13461348 .struct_type => {
13471349 const loaded_struct = ip.loadStructType(ty.toIntern());
13481350 switch (loaded_struct.layout) {
13491351 .auto, .@"extern" => {
13501352 if (!location.isInitializer()) {
1351 try writer.writeByte('(');
1352 try dg.renderCType(writer, ctype);
1353 try writer.writeByte(')');
1353 try w.writeByte('(');
1354 try dg.renderCType(w, ctype);
1355 try w.writeByte(')');
13541356 }
13551357
1356 try writer.writeByte('{');
1358 try w.writeByte('{');
13571359 var field_it = loaded_struct.iterateRuntimeOrder(ip);
13581360 var need_comma = false;
13591361 while (field_it.next()) |field_index| {
13601362 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
13611363 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13621364
1363 if (need_comma) try writer.writeByte(',');
1365 if (need_comma) try w.writeByte(',');
13641366 need_comma = true;
13651367 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
13661368 .bytes => |bytes| try pt.intern(.{ .int = .{
......@@ -1370,9 +1372,9 @@ pub const DeclGen = struct {
13701372 .elems => |elems| elems[field_index],
13711373 .repeated_elem => |elem| elem,
13721374 };
1373 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
1375 try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
13741376 }
1375 try writer.writeByte('}');
1377 try w.writeByte('}');
13761378 },
13771379 .@"packed" => {
13781380 const int_info = ty.intInfo(zcu);
......@@ -1390,16 +1392,16 @@ pub const DeclGen = struct {
13901392 }
13911393
13921394 if (eff_num_fields == 0) {
1393 try writer.writeByte('(');
1394 try dg.renderUndefValue(writer, ty, location);
1395 try writer.writeByte(')');
1395 try w.writeByte('(');
1396 try dg.renderUndefValue(w, ty, location);
1397 try w.writeByte(')');
13961398 } else if (ty.bitSize(zcu) > 64) {
13971399 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
13981400 var num_or = eff_num_fields - 1;
13991401 while (num_or > 0) : (num_or -= 1) {
1400 try writer.writeAll("zig_or_");
1401 try dg.renderTypeForBuiltinFnName(writer, ty);
1402 try writer.writeByte('(');
1402 try w.writeAll("zig_or_");
1403 try dg.renderTypeForBuiltinFnName(w, ty);
1404 try w.writeByte('(');
14031405 }
14041406
14051407 var eff_index: usize = 0;
......@@ -1418,36 +1420,36 @@ pub const DeclGen = struct {
14181420 };
14191421 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
14201422 if (bit_offset != 0) {
1421 try writer.writeAll("zig_shl_");
1422 try dg.renderTypeForBuiltinFnName(writer, ty);
1423 try writer.writeByte('(');
1424 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1425 try writer.writeAll(", ");
1426 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1427 try writer.writeByte(')');
1423 try w.writeAll("zig_shl_");
1424 try dg.renderTypeForBuiltinFnName(w, ty);
1425 try w.writeByte('(');
1426 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
1427 try w.writeAll(", ");
1428 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1429 try w.writeByte(')');
14281430 } else {
1429 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1431 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
14301432 }
14311433
1432 if (needs_closing_paren) try writer.writeByte(')');
1433 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1434 if (needs_closing_paren) try w.writeByte(')');
1435 if (eff_index != eff_num_fields - 1) try w.writeAll(", ");
14341436
14351437 bit_offset += field_ty.bitSize(zcu);
14361438 needs_closing_paren = true;
14371439 eff_index += 1;
14381440 }
14391441 } else {
1440 try writer.writeByte('(');
1442 try w.writeByte('(');
14411443 // a << a_off | b << b_off | c << c_off
14421444 var empty = true;
14431445 for (0..loaded_struct.field_types.len) |field_index| {
14441446 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
14451447 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
14461448
1447 if (!empty) try writer.writeAll(" | ");
1448 try writer.writeByte('(');
1449 try dg.renderCType(writer, ctype);
1450 try writer.writeByte(')');
1449 if (!empty) try w.writeAll(" | ");
1450 try w.writeByte('(');
1451 try dg.renderCType(w, ctype);
1452 try w.writeByte(')');
14511453
14521454 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
14531455 .bytes => |bytes| try pt.intern(.{ .int = .{
......@@ -1464,24 +1466,24 @@ pub const DeclGen = struct {
14641466 .{ .signedness = .unsigned, .bits = undefined };
14651467 switch (field_int_info.signedness) {
14661468 .signed => {
1467 try writer.writeByte('(');
1468 try dg.renderValue(writer, Value.fromInterned(field_val), .Other);
1469 try writer.writeAll(" & ");
1469 try w.writeByte('(');
1470 try dg.renderValue(w, Value.fromInterned(field_val), .Other);
1471 try w.writeAll(" & ");
14701472 const field_uint_ty = try pt.intType(.unsigned, field_int_info.bits);
1471 try dg.renderValue(writer, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
1472 try writer.writeByte(')');
1473 try dg.renderValue(w, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
1474 try w.writeByte(')');
14731475 },
1474 .unsigned => try dg.renderValue(writer, Value.fromInterned(field_val), .Other),
1476 .unsigned => try dg.renderValue(w, Value.fromInterned(field_val), .Other),
14751477 }
14761478 if (bit_offset != 0) {
1477 try writer.writeAll(" << ");
1478 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1479 try w.writeAll(" << ");
1480 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
14791481 }
14801482
14811483 bit_offset += field_ty.bitSize(zcu);
14821484 empty = false;
14831485 }
1484 try writer.writeByte(')');
1486 try w.writeByte(')');
14851487 }
14861488 },
14871489 }
......@@ -1495,11 +1497,11 @@ pub const DeclGen = struct {
14951497 switch (loaded_union.flagsUnordered(ip).layout) {
14961498 .@"packed" => {
14971499 if (!location.isInitializer()) {
1498 try writer.writeByte('(');
1499 try dg.renderType(writer, backing_ty);
1500 try writer.writeByte(')');
1500 try w.writeByte('(');
1501 try dg.renderType(w, backing_ty);
1502 try w.writeByte(')');
15011503 }
1502 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1504 try dg.renderValue(w, Value.fromInterned(un.val), location);
15031505 },
15041506 .@"extern" => {
15051507 if (location == .StaticInitializer) {
......@@ -1507,21 +1509,21 @@ pub const DeclGen = struct {
15071509 }
15081510
15091511 const ptr_ty = try pt.singleConstPtrType(ty);
1510 try writer.writeAll("*((");
1511 try dg.renderType(writer, ptr_ty);
1512 try writer.writeAll(")(");
1513 try dg.renderType(writer, backing_ty);
1514 try writer.writeAll("){");
1515 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1516 try writer.writeAll("})");
1512 try w.writeAll("*((");
1513 try dg.renderType(w, ptr_ty);
1514 try w.writeAll(")(");
1515 try dg.renderType(w, backing_ty);
1516 try w.writeAll("){");
1517 try dg.renderValue(w, Value.fromInterned(un.val), location);
1518 try w.writeAll("})");
15171519 },
15181520 else => unreachable,
15191521 }
15201522 } else {
15211523 if (!location.isInitializer()) {
1522 try writer.writeByte('(');
1523 try dg.renderCType(writer, ctype);
1524 try writer.writeByte(')');
1524 try w.writeByte('(');
1525 try dg.renderCType(w, ctype);
1526 try w.writeByte(')');
15251527 }
15261528
15271529 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
......@@ -1530,57 +1532,57 @@ pub const DeclGen = struct {
15301532 if (loaded_union.flagsUnordered(ip).layout == .@"packed") {
15311533 if (field_ty.hasRuntimeBits(zcu)) {
15321534 if (field_ty.isPtrAtRuntime(zcu)) {
1533 try writer.writeByte('(');
1534 try dg.renderCType(writer, ctype);
1535 try writer.writeByte(')');
1535 try w.writeByte('(');
1536 try dg.renderCType(w, ctype);
1537 try w.writeByte(')');
15361538 } else if (field_ty.zigTypeTag(zcu) == .float) {
1537 try writer.writeByte('(');
1538 try dg.renderCType(writer, ctype);
1539 try writer.writeByte(')');
1539 try w.writeByte('(');
1540 try dg.renderCType(w, ctype);
1541 try w.writeByte(')');
15401542 }
1541 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1542 } else try writer.writeByte('0');
1543 try dg.renderValue(w, Value.fromInterned(un.val), location);
1544 } else try w.writeByte('0');
15431545 return;
15441546 }
15451547
15461548 const has_tag = loaded_union.hasTag(ip);
1547 if (has_tag) try writer.writeByte('{');
1549 if (has_tag) try w.writeByte('{');
15481550 const aggregate = ctype.info(ctype_pool).aggregate;
15491551 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
1550 if (outer_field_index > 0) try writer.writeByte(',');
1552 if (outer_field_index > 0) try w.writeByte(',');
15511553 switch (if (has_tag)
15521554 aggregate.fields.at(outer_field_index, ctype_pool).name.index
15531555 else
15541556 .payload) {
15551557 .tag => try dg.renderValue(
1556 writer,
1558 w,
15571559 Value.fromInterned(un.tag),
15581560 initializer_type,
15591561 ),
15601562 .payload => {
1561 try writer.writeByte('{');
1563 try w.writeByte('{');
15621564 if (field_ty.hasRuntimeBits(zcu)) {
1563 try writer.print(" .{f } = ", .{fmtIdent(field_name.toSlice(ip))});
1565 try w.print(" .{f } = ", .{fmtIdent(field_name.toSlice(ip))});
15641566 try dg.renderValue(
1565 writer,
1567 w,
15661568 Value.fromInterned(un.val),
15671569 initializer_type,
15681570 );
1569 try writer.writeByte(' ');
1571 try w.writeByte(' ');
15701572 } else for (0..loaded_union.field_types.len) |inner_field_index| {
15711573 const inner_field_ty: Type = .fromInterned(
15721574 loaded_union.field_types.get(ip)[inner_field_index],
15731575 );
15741576 if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
1575 try dg.renderUndefValue(writer, inner_field_ty, initializer_type);
1577 try dg.renderUndefValue(w, inner_field_ty, initializer_type);
15761578 break;
15771579 }
1578 try writer.writeByte('}');
1580 try w.writeByte('}');
15791581 },
15801582 else => unreachable,
15811583 }
15821584 }
1583 if (has_tag) try writer.writeByte('}');
1585 if (has_tag) try w.writeByte('}');
15841586 }
15851587 },
15861588 }
......@@ -2999,18 +3001,20 @@ pub fn generate(
29993001 .pass = .{ .nav = func.owner_nav },
30003002 .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
30013003 .expected_block = null,
3002 .fwd_decl = .init(gpa),
3004 .fwd_decl = undefined,
30033005 .ctype_pool = .empty,
30043006 .scratch = .empty,
30053007 .uavs = .empty,
30063008 },
3007 .code = .init(gpa),
3008 .indent_writer = undefined, // set later so we can get a pointer to object.code
3009 .code_header = undefined,
3010 .code = undefined,
3011 .indent_counter = 0,
30093012 },
30103013 .lazy_fns = .empty,
30113014 };
30123015 defer {
3013 function.object.code.deinit();
3016 function.object.code_header.init(gpa);
3017 function.object.code.init(gpa);
30143018 function.object.dg.fwd_decl.deinit();
30153019 function.object.dg.ctype_pool.deinit(gpa);
30163020 function.object.dg.scratch.deinit(gpa);
......@@ -3018,7 +3022,9 @@ pub fn generate(
30183022 function.deinit();
30193023 }
30203024 try function.object.dg.ctype_pool.init(gpa);
3021 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
3025 function.object.dg.fwd_decl.init(gpa);
3026 function.object.code_header.init(gpa);
3027 function.object.code.init(gpa);
30223028
30233029 genFunc(&function) catch |err| switch (err) {
30243030 error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),
......@@ -3034,6 +3040,7 @@ pub fn generate(
30343040 };
30353041 errdefer mir.deinit(gpa);
30363042 mir.uavs = function.object.dg.uavs.move();
3043 mir.code_header = try function.object.code_header.toOwnedSlice();
30373044 mir.code = try function.object.code.toOwnedSlice();
30383045 mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();
30393046 mir.ctype_pool = function.object.dg.ctype_pool.move();
......@@ -3041,7 +3048,7 @@ pub fn generate(
30413048 return mir;
30423049}
30433050
3044fn genFunc(f: *Function) !void {
3051pub fn genFunc(f: *Function) Error!void {
30453052 const tracy = trace(@src());
30463053 defer tracy.end();
30473054
......@@ -4033,7 +4040,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
40334040 try f.writeCValueDeref(w, ret_val)
40344041 else
40354042 try f.writeCValue(w, ret_val, .Other);
4036 try w.writeAll(";\n");
4043 try w.write(";\n");
40374044 if (is_array) {
40384045 try freeLocal(f, inst, ret_val.new_local, null);
40394046 }
......@@ -4347,7 +4354,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
43474354 try f.writeCValue(w, rhs, .FunctionArgument);
43484355 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
43494356 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
4350 try w.writeAll(");\n");
4357 try w.writeAll(");");
4358 try f.object.newline();
43514359 try v.end(f, inst, w);
43524360
43534361 return local;
......@@ -4884,8 +4892,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
48844892 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
48854893 const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
48864894 const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
4887 const writer = f.object.writer();
4888 try writer.print("/* inline:{f} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4895 const w = &f.object.code.buffered_writer;
4896 try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4897 try f.object.newline();
48894898 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));
48904899}
48914900
......@@ -7415,30 +7424,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
74157424 const inst_ty = unwrapped.result_ty;
74167425 const elem_ty = inst_ty.childType(zcu);
74177426
7418 const writer = &f.object.code.buffered_writer;
7427 const w = &f.object.code.buffered_writer;
74197428 const local = try f.allocLocal(inst, inst_ty);
74207429 try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands
74217430 for (mask, 0..) |mask_elem, out_idx| {
7422 try f.writeCValue(writer, local, .Other);
7423 try writer.writeByte('[');
7424 try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other);
7425 try writer.writeAll("] = ");
7431 try f.writeCValue(w, local, .Other);
7432 try w.writeByte('[');
7433 try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
7434 try w.writeAll("] = ");
74267435 switch (mask_elem.unwrap()) {
74277436 .a_elem => |src_idx| {
7428 try f.writeCValue(writer, operand_a, .Other);
7429 try writer.writeByte('[');
7430 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
7431 try writer.writeByte(']');
7437 try f.writeCValue(w, operand_a, .Other);
7438 try w.writeByte('[');
7439 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7440 try w.writeByte(']');
74327441 },
74337442 .b_elem => |src_idx| {
7434 try f.writeCValue(writer, operand_b, .Other);
7435 try writer.writeByte('[');
7436 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
7437 try writer.writeByte(']');
7443 try f.writeCValue(w, operand_b, .Other);
7444 try w.writeByte('[');
7445 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7446 try w.writeByte(']');
74387447 },
7439 .undef => try f.object.dg.renderUndefValue(writer, elem_ty, .Other),
7448 .undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other),
74407449 }
7441 try writer.writeAll(";\n");
7450 try w.writeByte(';');
7451 try f.object.newline();
74427452 }
74437453
74447454 return local;
......@@ -7889,12 +7899,13 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
78897899
78907900fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
78917901 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7892 const writer = f.object.writer();
7902 const w = &f.object.code.buffered_writer;
78937903 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
7894 try f.writeCValue(writer, local, .Other);
7895 try writer.writeAll(" = ");
7896 try f.object.dg.renderNav(writer, ty_nav.nav, .Other);
7897 try writer.writeAll(";\n");
7904 try f.writeCValue(w, local, .Other);
7905 try w.writeAll(" = ");
7906 try f.object.dg.renderNav(w, ty_nav.nav, .Other);
7907 try w.writeByte(';');
7908 try f.object.newline();
78987909 return local;
78997910}
79007911
......@@ -8480,19 +8491,19 @@ const Assignment = struct {
84808491const Vectorize = struct {
84818492 index: CValue = .none,
84828493
8483 pub fn start(f: *Function, inst: Air.Inst.Index, writer: *Writer, ty: Type) !Vectorize {
8494 pub fn start(f: *Function, inst: Air.Inst.Index, w: *Writer, ty: Type) !Vectorize {
84848495 const pt = f.object.dg.pt;
84858496 const zcu = pt.zcu;
84868497 return if (ty.zigTypeTag(zcu) == .vector) index: {
84878498 const local = try f.allocLocal(inst, .usize);
84888499
8489 try writer.writeAll("for (");
8490 try f.writeCValue(writer, local, .Other);
8491 try writer.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});
8492 try f.writeCValue(writer, local, .Other);
8493 try writer.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
8494 try f.writeCValue(writer, local, .Other);
8495 try writer.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
8500 try w.writeAll("for (");
8501 try f.writeCValue(w, local, .Other);
8502 try w.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});
8503 try f.writeCValue(w, local, .Other);
8504 try w.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
8505 try f.writeCValue(w, local, .Other);
8506 try w.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
84968507 f.object.indent();
84978508 try f.object.newline();
84988509
src/link/C.zig+175-158
......@@ -25,34 +25,34 @@ base: link.File,
2525/// This linker backend does not try to incrementally link output C source code.
2626/// Instead, it tracks all declarations in this table, and iterates over it
2727/// in the flush function, stitching pre-rendered pieces of C code together.
28navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock) = .empty,
28navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock),
2929/// All the string bytes of rendered C code, all squished into one array.
3030/// While in progress, a separate buffer is used, and then when finished, the
3131/// buffer is copied into this one.
32string_bytes: std.ArrayListUnmanaged(u8) = .empty,
32string_bytes: std.ArrayListUnmanaged(u8),
3333/// Tracks all the anonymous decls that are used by all the decls so they can
3434/// be rendered during flush().
35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock) = .empty,
35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock),
3636/// Sparse set of uavs that are overaligned. Underaligned anon decls are
3737/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
3838/// the keys of `uavs`.
39aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty,
39aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
4040
41exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock) = .empty,
42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .empty,
41exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock),
42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock),
4343
4444/// Optimization, `updateDecl` reuses this buffer rather than creating a new
4545/// one with every call.
46fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
46fwd_decl_buf: []u8,
4747/// Optimization, `updateDecl` reuses this buffer rather than creating a new
4848/// one with every call.
49code_buf: std.ArrayListUnmanaged(u8) = .empty,
50/// Optimization, `flush` reuses this buffer rather than creating a new
49code_header_buf: []u8,
50/// Optimization, `updateDecl` reuses this buffer rather than creating a new
5151/// one with every call.
52lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
52code_buf: []u8,
5353/// Optimization, `flush` reuses this buffer rather than creating a new
5454/// one with every call.
55lazy_code_buf: std.ArrayListUnmanaged(u8) = .empty,
55scratch_buf: []u32,
5656
5757/// A reference into `string_bytes`.
5858const String = extern struct {
......@@ -67,11 +67,11 @@ const String = extern struct {
6767
6868/// Per-declaration data.
6969pub const AvBlock = struct {
70 code: String = String.empty,
71 fwd_decl: String = String.empty,
70 fwd_decl: String = .empty,
71 code: String = .empty,
7272 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
7373 /// over each `Decl` and generate the definition for each used `CType` once.
74 ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
74 ctype_pool: codegen.CType.Pool = .empty,
7575 /// May contain string references to ctype_pool
7676 lazy_fns: codegen.LazyFnMap = .{},
7777
......@@ -84,20 +84,21 @@ pub const AvBlock = struct {
8484
8585/// Per-exported-symbol data.
8686pub const ExportedBlock = struct {
87 fwd_decl: String = String.empty,
87 fwd_decl: String = .empty,
8888};
8989
9090pub fn getString(this: C, s: String) []const u8 {
9191 return this.string_bytes.items[s.start..][0..s.len];
9292}
9393
94pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
94pub fn addString(this: *C, writers: []const *std.io.AllocatingWriter) Allocator.Error!String {
9595 const comp = this.base.comp;
9696 const gpa = comp.gpa;
97 try this.string_bytes.appendSlice(gpa, s);
97 const start = this.string_bytes.items.len;
98 for (writers) |writer| try this.string_bytes.appendSlice(gpa, writer.getWritten());
9899 return .{
99 .start = @intCast(this.string_bytes.items.len - s.len),
100 .len = @intCast(s.len),
100 .start = @intCast(start),
101 .len = @intCast(this.string_bytes.items.len - start),
101102 };
102103}
103104
......@@ -147,6 +148,16 @@ pub fn createEmpty(
147148 .file = file,
148149 .build_id = options.build_id,
149150 },
151 .navs = .empty,
152 .string_bytes = .empty,
153 .uavs = .empty,
154 .aligned_uavs = .empty,
155 .exported_navs = .empty,
156 .exported_uavs = .empty,
157 .fwd_decl_buf = &.{},
158 .code_header_buf = &.{},
159 .code_buf = &.{},
160 .scratch_buf = &.{},
150161 };
151162
152163 return c_file;
......@@ -170,10 +181,10 @@ pub fn deinit(self: *C) void {
170181 self.exported_uavs.deinit(gpa);
171182
172183 self.string_bytes.deinit(gpa);
173 self.fwd_decl_buf.deinit(gpa);
174 self.code_buf.deinit(gpa);
175 self.lazy_fwd_decl_buf.deinit(gpa);
176 self.lazy_code_buf.deinit(gpa);
184 gpa.free(self.fwd_decl_buf);
185 gpa.free(self.code_header_buf);
186 gpa.free(self.code_buf);
187 gpa.free(self.scratch_buf);
177188}
178189
179190pub fn updateFunc(
......@@ -194,20 +205,15 @@ pub fn updateFunc(
194205 .ctype_pool = mir.c.ctype_pool.move(),
195206 .lazy_fns = mir.c.lazy_fns.move(),
196207 };
197 gop.value_ptr.code = try self.addString(mir.c.code);
198 gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl);
208 gop.value_ptr.fwd_decl = try self.addString(&.{&function.object.dg.fwd_decl});
209 gop.value_ptr.code = try self.addString(&.{ &function.object.code_header, &function.object.code });
199210 try self.addUavsFromCodegen(&mir.c.uavs);
200211}
201212
202fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
213fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) link.File.FlushError!void {
203214 const gpa = self.base.comp.gpa;
204215 const uav = self.uavs.keys()[i];
205216
206 const fwd_decl = &self.fwd_decl_buf;
207 const code = &self.code_buf;
208 fwd_decl.clearRetainingCapacity();
209 code.clearRetainingCapacity();
210
211217 var object: codegen.Object = .{
212218 .dg = .{
213219 .gpa = gpa,
......@@ -217,21 +223,24 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
217223 .pass = .{ .uav = uav },
218224 .is_naked_fn = false,
219225 .expected_block = null,
220 .fwd_decl = fwd_decl.toManaged(gpa),
221 .ctype_pool = codegen.CType.Pool.empty,
222 .scratch = .{},
226 .fwd_decl = undefined,
227 .ctype_pool = .empty,
228 .scratch = .initBuffer(self.scratch_buf),
223229 .uavs = .empty,
224230 },
225 .code = code.toManaged(gpa),
226 .indent_writer = undefined, // set later so we can get a pointer to object.code
231 .code_header = undefined,
232 .code = undefined,
233 .indent_counter = 0,
227234 };
228 object.indent_writer = .{ .underlying_writer = object.code.writer() };
235 object.dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
236 object.code.initOwnedSlice(gpa, self.code_buf);
229237 defer {
230238 object.dg.uavs.deinit(gpa);
231 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
232239 object.dg.ctype_pool.deinit(object.dg.gpa);
233 object.dg.scratch.deinit(gpa);
234 code.* = object.code.moveToUnmanaged();
240
241 self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
242 self.code_buf = object.code.toArrayList().allocatedSlice();
243 self.scratch_buf = object.dg.scratch.allocatedSlice();
235244 }
236245 try object.dg.ctype_pool.init(gpa);
237246
......@@ -243,15 +252,15 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
243252 //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
244253 //return;
245254 },
246 else => |e| return e,
255 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
247256 };
248257
249258 try self.addUavsFromCodegen(&object.dg.uavs);
250259
251260 object.dg.ctype_pool.freeUnusedCapacity(gpa);
252261 self.uavs.values()[i] = .{
253 .code = try self.addString(object.code.items),
254 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
262 .fwd_decl = try self.addString(&.{&object.dg.fwd_decl}),
263 .code = try self.addString(&.{&object.code}),
255264 .ctype_pool = object.dg.ctype_pool.move(),
256265 };
257266}
......@@ -277,12 +286,8 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
277286 errdefer _ = self.navs.pop();
278287 if (!gop.found_existing) gop.value_ptr.* = .{};
279288 const ctype_pool = &gop.value_ptr.ctype_pool;
280 const fwd_decl = &self.fwd_decl_buf;
281 const code = &self.code_buf;
282289 try ctype_pool.init(gpa);
283290 ctype_pool.clearRetainingCapacity();
284 fwd_decl.clearRetainingCapacity();
285 code.clearRetainingCapacity();
286291
287292 var object: codegen.Object = .{
288293 .dg = .{
......@@ -293,22 +298,25 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
293298 .pass = .{ .nav = nav_index },
294299 .is_naked_fn = false,
295300 .expected_block = null,
296 .fwd_decl = fwd_decl.toManaged(gpa),
301 .fwd_decl = undefined,
297302 .ctype_pool = ctype_pool.*,
298 .scratch = .{},
303 .scratch = .initBuffer(self.scratch_buf),
299304 .uavs = .empty,
300305 },
301 .code = code.toManaged(gpa),
302 .indent_writer = undefined, // set later so we can get a pointer to object.code
306 .code_header = undefined,
307 .code = undefined,
308 .indent_counter = 0,
303309 };
304 object.indent_writer = .{ .underlying_writer = object.code.writer() };
310 object.dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
311 object.code.initOwnedSlice(gpa, self.code_buf);
305312 defer {
306313 object.dg.uavs.deinit(gpa);
307 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
308314 ctype_pool.* = object.dg.ctype_pool.move();
309315 ctype_pool.freeUnusedCapacity(gpa);
310 object.dg.scratch.deinit(gpa);
311 code.* = object.code.moveToUnmanaged();
316
317 self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
318 self.code_buf = object.code.toArrayList().allocatedSlice();
319 self.scratch_buf = object.dg.scratch.allocatedSlice();
312320 }
313321
314322 codegen.genDecl(&object) catch |err| switch (err) {
......@@ -316,10 +324,10 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
316324 error.CodegenFail => return,
317325 error.OutOfMemory => |e| return e,
318326 },
319 else => |e| return e,
327 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
320328 };
321 gop.value_ptr.code = try self.addString(object.code.items);
322 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
329 gop.value_ptr.fwd_decl = try self.addString(&.{&object.dg.fwd_decl});
330 gop.value_ptr.code = try self.addString(&.{&object.code});
323331 try self.addUavsFromCodegen(&object.dg.uavs);
324332}
325333
......@@ -331,19 +339,14 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn
331339 _ = ti_id;
332340}
333341
334fn abiDefines(self: *C, target: *const std.Target) !std.ArrayList(u8) {
335 const gpa = self.base.comp.gpa;
336 var defines = std.ArrayList(u8).init(gpa);
337 errdefer defines.deinit();
338 const writer = defines.writer();
342fn abiDefines(bw: *std.io.BufferedWriter, target: std.Target) !void {
339343 switch (target.abi) {
340 .msvc, .itanium => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
344 .msvc, .itanium => try bw.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
341345 else => {},
342346 }
343 try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
347 try bw.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
344348 target.cMaxIntAlignment(),
345349 });
346 return defines;
347350}
348351
349352pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
......@@ -374,37 +377,49 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
374377 // emit-h is in `flushEmitH` below.
375378
376379 var f: Flush = .{
377 .ctype_pool = codegen.CType.Pool.empty,
378 .lazy_ctype_pool = codegen.CType.Pool.empty,
380 .ctype_pool = .empty,
381 .ctype_global_from_decl_map = .empty,
382 .ctypes = .empty,
383
384 .lazy_ctype_pool = .empty,
385 .lazy_fns = .empty,
386 .lazy_fwd_decl = .empty,
387 .lazy_code = .empty,
388
389 .all_buffers = .empty,
390 .file_size = 0,
379391 };
380392 defer f.deinit(gpa);
381393
382 const abi_defines = try self.abiDefines(zcu.getTarget());
383 defer abi_defines.deinit();
394 var abi_defines_aw: std.io.AllocatingWriter = undefined;
395 abi_defines_aw.init(gpa);
396 defer abi_defines_aw.deinit();
397 abiDefines(&abi_defines_aw.buffered_writer, zcu.getTarget()) catch |err| switch (err) {
398 error.WriteFailed => return error.OutOfMemory,
399 };
384400
385401 // Covers defines, zig.h, ctypes, asm, lazy fwd.
386402 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
387403
388 f.appendBufAssumeCapacity(abi_defines.items);
404 f.appendBufAssumeCapacity(abi_defines_aw.getWritten());
389405 f.appendBufAssumeCapacity(zig_h);
390406
391407 const ctypes_index = f.all_buffers.items.len;
392408 f.all_buffers.items.len += 1;
393409
394 {
395 var asm_buf = f.asm_buf.toManaged(gpa);
396 defer f.asm_buf = asm_buf.moveToUnmanaged();
397 try codegen.genGlobalAsm(zcu, asm_buf.writer());
398 f.appendBufAssumeCapacity(asm_buf.items);
399 }
410 var asm_aw: std.io.AllocatingWriter = undefined;
411 asm_aw.init(gpa);
412 defer asm_aw.deinit();
413 codegen.genGlobalAsm(zcu, &asm_aw.buffered_writer) catch |err| switch (err) {
414 error.WriteFailed => return error.OutOfMemory,
415 };
416 f.appendBufAssumeCapacity(asm_aw.getWritten());
400417
401418 const lazy_index = f.all_buffers.items.len;
402419 f.all_buffers.items.len += 1;
403420
404 self.lazy_fwd_decl_buf.clearRetainingCapacity();
405 self.lazy_code_buf.clearRetainingCapacity();
406421 try f.lazy_ctype_pool.init(gpa);
407 try self.flushErrDecls(pt, &f.lazy_ctype_pool);
422 try self.flushErrDecls(pt, &f);
408423
409424 // Unlike other backends, the .c code we are emitting has order-dependent decls.
410425 // `CType`s, forward decls, and non-functions first.
......@@ -462,22 +477,15 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
462477 }
463478 }
464479
465 f.all_buffers.items[ctypes_index] = .{
466 .base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
467 .len = f.ctypes_buf.items.len,
468 };
469 f.file_size += f.ctypes_buf.items.len;
480 f.all_buffers.items[ctypes_index] = f.ctypes.items;
481 f.file_size += f.ctypes.items.len;
470482
471 const lazy_fwd_decl_len = self.lazy_fwd_decl_buf.items.len;
472 f.all_buffers.items[lazy_index] = .{
473 .base = if (lazy_fwd_decl_len > 0) self.lazy_fwd_decl_buf.items.ptr else "",
474 .len = lazy_fwd_decl_len,
475 };
476 f.file_size += lazy_fwd_decl_len;
483 f.all_buffers.items[lazy_index] = f.lazy_fwd_decl.items;
484 f.file_size += f.lazy_fwd_decl.items.len;
477485
478486 // Now the code.
479487 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);
480 f.appendBufAssumeCapacity(self.lazy_code_buf.items);
488 f.appendBufAssumeCapacity(f.lazy_code.items);
481489 for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
482490 if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
483491 .@"extern" => .zig_extern,
......@@ -493,31 +501,35 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
493501
494502 const file = self.base.file.?;
495503 file.setEndPos(f.file_size) catch |err| return diags.fail("failed to allocate file: {s}", .{@errorName(err)});
496 file.pwritevAll(f.all_buffers.items, 0) catch |err| return diags.fail("failed to write to '{'}': {s}", .{
497 self.base.emit, @errorName(err),
498 });
504 var fw = file.writer();
505 var bw = fw.interface().unbuffered();
506 bw.writeVecAll(f.all_buffers.items) catch |err| switch (err) {
507 error.WriteFailed => return diags.fail("failed to write to '{f'}': {s}", .{
508 self.base.emit, @errorName(fw.err.?),
509 }),
510 };
499511}
500512
501513const Flush = struct {
502514 ctype_pool: codegen.CType.Pool,
503 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .empty,
504 ctypes_buf: std.ArrayListUnmanaged(u8) = .empty,
515 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType),
516 ctypes: std.ArrayListUnmanaged(u8),
505517
506518 lazy_ctype_pool: codegen.CType.Pool,
507 lazy_fns: LazyFns = .{},
508
509 asm_buf: std.ArrayListUnmanaged(u8) = .empty,
519 lazy_fns: LazyFns,
520 lazy_fwd_decl: std.ArrayListUnmanaged(u8),
521 lazy_code: std.ArrayListUnmanaged(u8),
510522
511523 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
512 all_buffers: std.ArrayListUnmanaged(std.posix.iovec_const) = .empty,
524 all_buffers: std.ArrayListUnmanaged([]const u8),
513525 /// Keeps track of the total bytes of `all_buffers`.
514 file_size: u64 = 0,
526 file_size: u64,
515527
516528 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
517529
518530 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
519531 if (buf.len == 0) return;
520 f.all_buffers.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });
532 f.all_buffers.appendAssumeCapacity(buf);
521533 f.file_size += buf.len;
522534 }
523535
......@@ -532,14 +544,15 @@ const Flush = struct {
532544 }
533545
534546 fn deinit(f: *Flush, gpa: Allocator) void {
535 f.all_buffers.deinit(gpa);
536 f.asm_buf.deinit(gpa);
537 f.lazy_fns.deinit(gpa);
538 f.lazy_ctype_pool.deinit(gpa);
539 f.ctypes_buf.deinit(gpa);
547 f.ctype_pool.deinit(gpa);
540548 assert(f.ctype_global_from_decl_map.items.len == 0);
541549 f.ctype_global_from_decl_map.deinit(gpa);
542 f.ctype_pool.deinit(gpa);
550 f.ctypes.deinit(gpa);
551 f.lazy_ctype_pool.deinit(gpa);
552 f.lazy_fns.deinit(gpa);
553 f.lazy_fwd_decl.deinit(gpa);
554 f.lazy_code.deinit(gpa);
555 f.all_buffers.deinit(gpa);
543556 }
544557};
545558
......@@ -562,9 +575,9 @@ fn flushCTypes(
562575 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
563576 defer global_from_decl_map.clearRetainingCapacity();
564577
565 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
566 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
567 const writer = ctypes_buf.writer();
578 var ctypes_aw: std.io.AllocatingWriter = undefined;
579 const ctypes_bw = ctypes_aw.fromArrayList(gpa, &f.ctypes);
580 defer f.ctypes = ctypes_aw.toArrayList();
568581
569582 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
570583 const PoolAdapter = struct {
......@@ -591,26 +604,25 @@ fn flushCTypes(
591604 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
592605 );
593606 global_from_decl_map.appendAssumeCapacity(global_ctype);
594 try codegen.genTypeDecl(
607 codegen.genTypeDecl(
595608 zcu,
596 writer,
609 ctypes_bw,
597610 global_ctype_pool,
598611 global_ctype,
599612 pass,
600613 decl_ctype_pool,
601614 decl_ctype,
602615 found_existing,
603 );
616 ) catch |err| switch (err) {
617 error.WriteFailed => return error.OutOfMemory,
618 };
604619 }
605620}
606621
607fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) FlushDeclError!void {
622fn flushErrDecls(self: *C, pt: Zcu.PerThread, f: *Flush) FlushDeclError!void {
608623 const gpa = self.base.comp.gpa;
609624
610 const fwd_decl = &self.lazy_fwd_decl_buf;
611 const code = &self.lazy_code_buf;
612
613 var object = codegen.Object{
625 var object: codegen.Object = .{
614626 .dg = .{
615627 .gpa = gpa,
616628 .pt = pt,
......@@ -619,27 +631,30 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F
619631 .pass = .flush,
620632 .is_naked_fn = false,
621633 .expected_block = null,
622 .fwd_decl = fwd_decl.toManaged(gpa),
623 .ctype_pool = ctype_pool.*,
624 .scratch = .{},
634 .fwd_decl = undefined,
635 .ctype_pool = f.lazy_ctype_pool,
636 .scratch = .initBuffer(self.scratch_buf),
625637 .uavs = .empty,
626638 },
627 .code = code.toManaged(gpa),
628 .indent_writer = undefined, // set later so we can get a pointer to object.code
639 .code_header = undefined,
640 .code = undefined,
641 .indent_counter = 0,
629642 };
630 object.indent_writer = .{ .underlying_writer = object.code.writer() };
643 _ = object.dg.fwd_decl.fromArrayList(gpa, &f.lazy_fwd_decl);
644 _ = object.code.fromArrayList(gpa, &f.lazy_code);
631645 defer {
632646 object.dg.uavs.deinit(gpa);
633 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
634 ctype_pool.* = object.dg.ctype_pool.move();
635 ctype_pool.freeUnusedCapacity(gpa);
636 object.dg.scratch.deinit(gpa);
637 code.* = object.code.moveToUnmanaged();
647 f.lazy_ctype_pool = object.dg.ctype_pool.move();
648 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
649
650 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
651 f.lazy_code = object.code.toArrayList();
652 self.scratch_buf = object.dg.scratch.allocatedSlice();
638653 }
639654
640655 codegen.genErrDecls(&object) catch |err| switch (err) {
641656 error.AnalysisFail => unreachable,
642 else => |e| return e,
657 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
643658 };
644659
645660 try self.addUavsFromCodegen(&object.dg.uavs);
......@@ -649,16 +664,13 @@ fn flushLazyFn(
649664 self: *C,
650665 pt: Zcu.PerThread,
651666 mod: *Module,
652 ctype_pool: *codegen.CType.Pool,
667 f: *Flush,
653668 lazy_ctype_pool: *const codegen.CType.Pool,
654669 lazy_fn: codegen.LazyFnMap.Entry,
655670) FlushDeclError!void {
656671 const gpa = self.base.comp.gpa;
657672
658 const fwd_decl = &self.lazy_fwd_decl_buf;
659 const code = &self.lazy_code_buf;
660
661 var object = codegen.Object{
673 var object: codegen.Object = .{
662674 .dg = .{
663675 .gpa = gpa,
664676 .pt = pt,
......@@ -667,29 +679,32 @@ fn flushLazyFn(
667679 .pass = .flush,
668680 .is_naked_fn = false,
669681 .expected_block = null,
670 .fwd_decl = fwd_decl.toManaged(gpa),
671 .ctype_pool = ctype_pool.*,
672 .scratch = .{},
682 .fwd_decl = undefined,
683 .ctype_pool = f.lazy_ctype_pool,
684 .scratch = .initBuffer(self.scratch_buf),
673685 .uavs = .empty,
674686 },
675 .code = code.toManaged(gpa),
676 .indent_writer = undefined, // set later so we can get a pointer to object.code
687 .code_header = undefined,
688 .code = undefined,
689 .indent_counter = 0,
677690 };
678 object.indent_writer = .{ .underlying_writer = object.code.writer() };
691 _ = object.dg.fwd_decl.fromArrayList(gpa, &f.lazy_fwd_decl);
692 _ = object.code.fromArrayList(gpa, &f.lazy_code);
679693 defer {
680694 // If this assert trips just handle the anon_decl_deps the same as
681695 // `updateFunc()` does.
682696 assert(object.dg.uavs.count() == 0);
683 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
684 ctype_pool.* = object.dg.ctype_pool.move();
685 ctype_pool.freeUnusedCapacity(gpa);
686 object.dg.scratch.deinit(gpa);
687 code.* = object.code.moveToUnmanaged();
697 f.lazy_ctype_pool = object.dg.ctype_pool.move();
698 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
699
700 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
701 f.lazy_code = object.code.toArrayList();
702 self.scratch_buf = object.dg.scratch.allocatedSlice();
688703 }
689704
690705 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
691706 error.AnalysisFail => unreachable,
692 else => |e| return e,
707 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
693708 };
694709}
695710
......@@ -709,7 +724,7 @@ fn flushLazyFns(
709724 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
710725 if (gop.found_existing) continue;
711726 gop.value_ptr.* = {};
712 try self.flushLazyFn(pt, mod, &f.lazy_ctype_pool, lazy_ctype_pool, entry);
727 try self.flushLazyFn(pt, mod, f, lazy_ctype_pool, entry);
713728 }
714729}
715730
......@@ -802,8 +817,6 @@ pub fn updateExports(
802817 },
803818 };
804819 const ctype_pool = &decl_block.ctype_pool;
805 const fwd_decl = &self.fwd_decl_buf;
806 fwd_decl.clearRetainingCapacity();
807820 var dg: codegen.DeclGen = .{
808821 .gpa = gpa,
809822 .pt = pt,
......@@ -812,20 +825,24 @@ pub fn updateExports(
812825 .pass = pass,
813826 .is_naked_fn = false,
814827 .expected_block = null,
815 .fwd_decl = fwd_decl.toManaged(gpa),
828 .fwd_decl = undefined,
816829 .ctype_pool = decl_block.ctype_pool,
817 .scratch = .{},
830 .scratch = .initBuffer(self.scratch_buf),
818831 .uavs = .empty,
819832 };
833 dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
820834 defer {
821835 assert(dg.uavs.count() == 0);
822 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
823836 ctype_pool.* = dg.ctype_pool.move();
824837 ctype_pool.freeUnusedCapacity(gpa);
825 dg.scratch.deinit(gpa);
838
839 self.fwd_decl_buf = dg.fwd_decl.toArrayList().allocatedSlice();
840 self.scratch_buf = dg.scratch.allocatedSlice();
826841 }
827 try codegen.genExports(&dg, exported, export_indices);
828 exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };
842 codegen.genExports(&dg, exported, export_indices) catch |err| switch (err) {
843 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
844 };
845 exported_block.* = .{ .fwd_decl = try self.addString(&.{&dg.fwd_decl}) };
829846}
830847
831848pub fn deleteExport(