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 {...@@ -56,6 +56,7 @@ pub const Mir = struct {
56 /// less than the natural alignment.56 /// less than the natural alignment.
57 uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),57 uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
58 // These remaining fields are essentially just an owned version of `link.C.AvBlock`.58 // These remaining fields are essentially just an owned version of `link.C.AvBlock`.
59 code_header: []u8,
59 code: []u8,60 code: []u8,
60 fwd_decl: []u8,61 fwd_decl: []u8,
61 ctype_pool: CType.Pool,62 ctype_pool: CType.Pool,
...@@ -63,6 +64,7 @@ pub const Mir = struct {...@@ -63,6 +64,7 @@ pub const Mir = struct {
6364
64 pub fn deinit(mir: *Mir, gpa: Allocator) void {65 pub fn deinit(mir: *Mir, gpa: Allocator) void {
65 mir.uavs.deinit(gpa);66 mir.uavs.deinit(gpa);
67 gpa.free(mir.code_header);
66 gpa.free(mir.code);68 gpa.free(mir.code);
67 gpa.free(mir.fwd_decl);69 gpa.free(mir.fwd_decl);
68 mir.ctype_pool.deinit(gpa);70 mir.ctype_pool.deinit(gpa);
...@@ -345,23 +347,23 @@ fn isReservedIdent(ident: []const u8) bool {...@@ -345,23 +347,23 @@ fn isReservedIdent(ident: []const u8) bool {
345347
346fn formatIdent(348fn formatIdent(
347 ident: []const u8,349 ident: []const u8,
348 writer: *Writer,350 w: *Writer,
349 comptime fmt_str: []const u8,351 comptime fmt_str: []const u8,
350) Writer.Error!void {352) Writer.Error!void {
351 const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.353 const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
352 if (solo and isReservedIdent(ident)) {354 if (solo and isReservedIdent(ident)) {
353 try writer.writeAll("zig_e_");355 try w.writeAll("zig_e_");
354 }356 }
355 for (ident, 0..) |c, i| {357 for (ident, 0..) |c, i| {
356 switch (c) {358 switch (c) {
357 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),359 'a'...'z', 'A'...'Z', '_' => try w.writeByte(c),
358 '.' => try writer.writeByte('_'),360 '.' => try w.writeByte('_'),
359 '0'...'9' => if (i == 0) {361 '0'...'9' => if (i == 0) {
360 try writer.print("_{x:2}", .{c});362 try w.print("_{x:2}", .{c});
361 } else {363 } else {
362 try writer.writeByte(c);364 try w.writeByte(c);
363 },365 },
364 else => try writer.print("_{x:2}", .{c}),366 else => try w.print("_{x:2}", .{c}),
365 }367 }
366 }368 }
367}369}
...@@ -375,13 +377,13 @@ const CTypePoolStringFormatData = struct {...@@ -375,13 +377,13 @@ const CTypePoolStringFormatData = struct {
375};377};
376fn formatCTypePoolString(378fn formatCTypePoolString(
377 data: CTypePoolStringFormatData,379 data: CTypePoolStringFormatData,
378 writer: *Writer,380 w: *Writer,
379 comptime fmt_str: []const u8,381 comptime fmt_str: []const u8,
380) Writer.Error!void {382) Writer.Error!void {
381 if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|383 if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
382 try formatIdent(slice, writer, fmt_str)384 try formatIdent(slice, w, fmt_str)
383 else385 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)});
385}387}
386pub fn fmtCTypePoolString(388pub fn fmtCTypePoolString(
387 ctype_pool_string: CType.Pool.String,389 ctype_pool_string: CType.Pool.String,
...@@ -441,18 +443,18 @@ pub const Function = struct {...@@ -441,18 +443,18 @@ pub const Function = struct {
441 const ty = f.typeOf(ref);443 const ty = f.typeOf(ref);
442444
443 const result: CValue = if (lowersToArray(ty, pt)) result: {445 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;
445 const decl_c_value = try f.allocLocalValue(.{447 const decl_c_value = try f.allocLocalValue(.{
446 .ctype = try f.ctypeFromType(ty, .complete),448 .ctype = try f.ctypeFromType(ty, .complete),
447 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),449 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
448 });450 });
449 const gpa = f.object.dg.gpa;451 const gpa = f.object.dg.gpa;
450 try f.allocs.put(gpa, decl_c_value.new_local, false);452 try f.allocs.put(gpa, decl_c_value.new_local, false);
451 try writer.writeAll("static ");453 try ch.writeAll("static ");
452 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);454 try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete);
453 try writer.writeAll(" = ");455 try ch.writeAll(" = ");
454 try f.object.dg.renderValue(writer, val, .StaticInitializer);456 try f.object.dg.renderValue(ch, val, .StaticInitializer);
455 try writer.writeAll(";\n ");457 try ch.writeAll(";\n ");
456 break :result .{ .local = decl_c_value.new_local };458 break :result .{ .local = decl_c_value.new_local };
457 } else .{ .constant = val };459 } else .{ .constant = val };
458460
...@@ -979,7 +981,7 @@ pub const DeclGen = struct {...@@ -979,7 +981,7 @@ pub const DeclGen = struct {
979981
980 fn renderValue(982 fn renderValue(
981 dg: *DeclGen,983 dg: *DeclGen,
982 writer: *Writer,984 w: *Writer,
983 val: Value,985 val: Value,
984 location: ValueRenderLocation,986 location: ValueRenderLocation,
985 ) Error!void {987 ) Error!void {
...@@ -995,7 +997,7 @@ pub const DeclGen = struct {...@@ -995,7 +997,7 @@ pub const DeclGen = struct {
995 };997 };
996998
997 const ty = val.typeOf(zcu);999 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);
999 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());1001 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
1000 switch (ip.indexToKey(val.toIntern())) {1002 switch (ip.indexToKey(val.toIntern())) {
1001 // types, not values1003 // types, not values
...@@ -1028,8 +1030,8 @@ pub const DeclGen = struct {...@@ -1028,8 +1030,8 @@ pub const DeclGen = struct {
1028 .empty_tuple => unreachable,1030 .empty_tuple => unreachable,
1029 .@"unreachable" => unreachable,1031 .@"unreachable" => unreachable,
10301032
1031 .false => try writer.writeAll("false"),1033 .false => try w.writeAll("false"),
1032 .true => try writer.writeAll("true"),1034 .true => try w.writeAll("true"),
1033 },1035 },
1034 .variable,1036 .variable,
1035 .@"extern",1037 .@"extern",
...@@ -1038,45 +1040,45 @@ pub const DeclGen = struct {...@@ -1038,45 +1040,45 @@ pub const DeclGen = struct {
1038 .empty_enum_value,1040 .empty_enum_value,
1039 => unreachable, // non-runtime values1041 => unreachable, // non-runtime values
1040 .int => |int| switch (int.storage) {1042 .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)}),
1042 .lazy_align, .lazy_size => {1044 .lazy_align, .lazy_size => {
1043 try writer.writeAll("((");1045 try w.writeAll("((");
1044 try dg.renderCType(writer, ctype);1046 try dg.renderCType(w, ctype);
1045 try writer.print("){fx})", .{try dg.fmtIntLiteral(1047 try w.print("){fx})", .{try dg.fmtIntLiteral(
1046 try pt.intValue(.usize, val.toUnsignedInt(zcu)),1048 try pt.intValue(.usize, val.toUnsignedInt(zcu)),
1047 .Other,1049 .Other,
1048 )});1050 )});
1049 },1051 },
1050 },1052 },
1051 .err => |err| try dg.renderErrorName(writer, err.name),1053 .err => |err| try dg.renderErrorName(w, err.name),
1052 .error_union => |error_union| switch (ctype.info(ctype_pool)) {1054 .error_union => |error_union| switch (ctype.info(ctype_pool)) {
1053 .basic => switch (error_union.val) {1055 .basic => switch (error_union.val) {
1054 .err_name => |err_name| try dg.renderErrorName(writer, err_name),1056 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1055 .payload => try writer.writeByte('0'),1057 .payload => try w.writeByte('0'),
1056 },1058 },
1057 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,1059 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
1058 .aggregate => |aggregate| {1060 .aggregate => |aggregate| {
1059 if (!location.isInitializer()) {1061 if (!location.isInitializer()) {
1060 try writer.writeByte('(');1062 try w.writeByte('(');
1061 try dg.renderCType(writer, ctype);1063 try dg.renderCType(w, ctype);
1062 try writer.writeByte(')');1064 try w.writeByte(')');
1063 }1065 }
1064 try writer.writeByte('{');1066 try w.writeByte('{');
1065 for (0..aggregate.fields.len) |field_index| {1067 for (0..aggregate.fields.len) |field_index| {
1066 if (field_index > 0) try writer.writeByte(',');1068 if (field_index > 0) try w.writeByte(',');
1067 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {1069 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1068 .@"error" => switch (error_union.val) {1070 .@"error" => switch (error_union.val) {
1069 .err_name => |err_name| try dg.renderErrorName(writer, err_name),1071 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1070 .payload => try writer.writeByte('0'),1072 .payload => try w.writeByte('0'),
1071 },1073 },
1072 .payload => switch (error_union.val) {1074 .payload => switch (error_union.val) {
1073 .err_name => try dg.renderUndefValue(1075 .err_name => try dg.renderUndefValue(
1074 writer,1076 w,
1075 ty.errorUnionPayload(zcu),1077 ty.errorUnionPayload(zcu),
1076 initializer_type,1078 initializer_type,
1077 ),1079 ),
1078 .payload => |payload| try dg.renderValue(1080 .payload => |payload| try dg.renderValue(
1079 writer,1081 w,
1080 Value.fromInterned(payload),1082 Value.fromInterned(payload),
1081 initializer_type,1083 initializer_type,
1082 ),1084 ),
...@@ -1084,10 +1086,10 @@ pub const DeclGen = struct {...@@ -1084,10 +1086,10 @@ pub const DeclGen = struct {
1084 else => unreachable,1086 else => unreachable,
1085 }1087 }
1086 }1088 }
1087 try writer.writeByte('}');1089 try w.writeByte('}');
1088 },1090 },
1089 },1091 },
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),
1091 .float => {1093 .float => {
1092 const bits = ty.floatBits(target);1094 const bits = ty.floatBits(target);
1093 const f128_val = val.toFloat(f128, zcu);1095 const f128_val = val.toFloat(f128, zcu);
...@@ -1114,18 +1116,18 @@ pub const DeclGen = struct {...@@ -1114,18 +1116,18 @@ pub const DeclGen = struct {
11141116
1115 var empty = true;1117 var empty = true;
1116 if (std.math.isFinite(f128_val)) {1118 if (std.math.isFinite(f128_val)) {
1117 try writer.writeAll("zig_make_");1119 try w.writeAll("zig_make_");
1118 try dg.renderTypeForBuiltinFnName(writer, ty);1120 try dg.renderTypeForBuiltinFnName(w, ty);
1119 try writer.writeByte('(');1121 try w.writeByte('(');
1120 switch (bits) {1122 switch (bits) {
1121 16 => try writer.print("{x}", .{val.toFloat(f16, zcu)}),1123 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}),
1122 32 => try writer.print("{x}", .{val.toFloat(f32, zcu)}),1124 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}),
1123 64 => try writer.print("{x}", .{val.toFloat(f64, zcu)}),1125 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}),
1124 80 => try writer.print("{x}", .{val.toFloat(f80, zcu)}),1126 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}),
1125 128 => try writer.print("{x}", .{f128_val}),1127 128 => try w.print("{x}", .{f128_val}),
1126 else => unreachable,1128 else => unreachable,
1127 }1129 }
1128 try writer.writeAll(", ");1130 try w.writeAll(", ");
1129 empty = false;1131 empty = false;
1130 } else {1132 } else {
1131 // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan1133 // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan
...@@ -1149,45 +1151,45 @@ pub const DeclGen = struct {...@@ -1149,45 +1151,45 @@ pub const DeclGen = struct {
1149 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});1151 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});
1150 }1152 }
11511153
1152 try writer.writeAll("zig_");1154 try w.writeAll("zig_");
1153 try writer.writeAll(if (location == .StaticInitializer) "init" else "make");1155 try w.writeAll(if (location == .StaticInitializer) "init" else "make");
1154 try writer.writeAll("_special_");1156 try w.writeAll("_special_");
1155 try dg.renderTypeForBuiltinFnName(writer, ty);1157 try dg.renderTypeForBuiltinFnName(w, ty);
1156 try writer.writeByte('(');1158 try w.writeByte('(');
1157 if (std.math.signbit(f128_val)) try writer.writeByte('-');1159 if (std.math.signbit(f128_val)) try w.writeByte('-');
1158 try writer.writeAll(", ");1160 try w.writeAll(", ");
1159 try writer.writeAll(operation);1161 try w.writeAll(operation);
1160 try writer.writeAll(", ");1162 try w.writeAll(", ");
1161 if (std.math.isNan(f128_val)) switch (bits) {1163 if (std.math.isNan(f128_val)) switch (bits) {
1162 // We only actually need to pass the significand, but it will get1164 // We only actually need to pass the significand, but it will get
1163 // properly masked anyway, so just pass the whole value.1165 // properly masked anyway, so just pass the whole value.
1164 16 => try writer.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),1166 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
1165 32 => try writer.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),1167 32 => try w.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
1166 64 => try writer.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),1168 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
1167 80 => try writer.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),1169 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
1168 128 => try writer.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),1170 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
1169 else => unreachable,1171 else => unreachable,
1170 };1172 };
1171 try writer.writeAll(", ");1173 try w.writeAll(", ");
1172 empty = false;1174 empty = false;
1173 }1175 }
1174 try writer.print("{fx}", .{try dg.fmtIntLiteral(1176 try w.print("{fx}", .{try dg.fmtIntLiteral(
1175 try pt.intValue_big(repr_ty, repr_val_big.toConst()),1177 try pt.intValue_big(repr_ty, repr_val_big.toConst()),
1176 location,1178 location,
1177 )});1179 )});
1178 if (!empty) try writer.writeByte(')');1180 if (!empty) try w.writeByte(')');
1179 },1181 },
1180 .slice => |slice| {1182 .slice => |slice| {
1181 const aggregate = ctype.info(ctype_pool).aggregate;1183 const aggregate = ctype.info(ctype_pool).aggregate;
1182 if (!location.isInitializer()) {1184 if (!location.isInitializer()) {
1183 try writer.writeByte('(');1185 try w.writeByte('(');
1184 try dg.renderCType(writer, ctype);1186 try dg.renderCType(w, ctype);
1185 try writer.writeByte(')');1187 try w.writeByte(')');
1186 }1188 }
1187 try writer.writeByte('{');1189 try w.writeByte('{');
1188 for (0..aggregate.fields.len) |field_index| {1190 for (0..aggregate.fields.len) |field_index| {
1189 if (field_index > 0) try writer.writeByte(',');1191 if (field_index > 0) try w.writeByte(',');
1190 try dg.renderValue(writer, Value.fromInterned(1192 try dg.renderValue(w, Value.fromInterned(
1191 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {1193 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1192 .ptr => slice.ptr,1194 .ptr => slice.ptr,
1193 .len => slice.len,1195 .len => slice.len,
...@@ -1195,33 +1197,33 @@ pub const DeclGen = struct {...@@ -1195,33 +1197,33 @@ pub const DeclGen = struct {
1195 },1197 },
1196 ), initializer_type);1198 ), initializer_type);
1197 }1199 }
1198 try writer.writeByte('}');1200 try w.writeByte('}');
1199 },1201 },
1200 .ptr => {1202 .ptr => {
1201 var arena = std.heap.ArenaAllocator.init(zcu.gpa);1203 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
1202 defer arena.deinit();1204 defer arena.deinit();
1203 const derivation = try val.pointerDerivation(arena.allocator(), pt);1205 const derivation = try val.pointerDerivation(arena.allocator(), pt);
1204 try dg.renderPointer(writer, derivation, location);1206 try dg.renderPointer(w, derivation, location);
1205 },1207 },
1206 .opt => |opt| switch (ctype.info(ctype_pool)) {1208 .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) {
1208 .none => "true",1210 .none => "true",
1209 else => "false",1211 else => "false",
1210 }) else switch (opt.val) {1212 }) else switch (opt.val) {
1211 .none => try writer.writeByte('0'),1213 .none => try w.writeByte('0'),
1212 else => |payload| switch (ip.indexToKey(payload)) {1214 else => |payload| switch (ip.indexToKey(payload)) {
1213 .undef => |err_ty| try dg.renderUndefValue(1215 .undef => |err_ty| try dg.renderUndefValue(
1214 writer,1216 w,
1215 .fromInterned(err_ty),1217 .fromInterned(err_ty),
1216 location,1218 location,
1217 ),1219 ),
1218 .err => |err| try dg.renderErrorName(writer, err.name),1220 .err => |err| try dg.renderErrorName(w, err.name),
1219 else => unreachable,1221 else => unreachable,
1220 },1222 },
1221 },1223 },
1222 .pointer => switch (opt.val) {1224 .pointer => switch (opt.val) {
1223 .none => try writer.writeAll("NULL"),1225 .none => try w.writeAll("NULL"),
1224 else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),1226 else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location),
1225 },1227 },
1226 .aligned, .array, .vector, .fwd_decl, .function => unreachable,1228 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
1227 .aggregate => |aggregate| {1229 .aggregate => |aggregate| {
...@@ -1230,7 +1232,7 @@ pub const DeclGen = struct {...@@ -1230,7 +1232,7 @@ pub const DeclGen = struct {
1230 else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {1232 else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
1231 .is_null, .payload => {},1233 .is_null, .payload => {},
1232 .ptr, .len => return dg.renderValue(1234 .ptr, .len => return dg.renderValue(
1233 writer,1235 w,
1234 Value.fromInterned(payload),1236 Value.fromInterned(payload),
1235 location,1237 location,
1236 ),1238 ),
...@@ -1238,48 +1240,48 @@ pub const DeclGen = struct {...@@ -1238,48 +1240,48 @@ pub const DeclGen = struct {
1238 },1240 },
1239 }1241 }
1240 if (!location.isInitializer()) {1242 if (!location.isInitializer()) {
1241 try writer.writeByte('(');1243 try w.writeByte('(');
1242 try dg.renderCType(writer, ctype);1244 try dg.renderCType(w, ctype);
1243 try writer.writeByte(')');1245 try w.writeByte(')');
1244 }1246 }
1245 try writer.writeByte('{');1247 try w.writeByte('{');
1246 for (0..aggregate.fields.len) |field_index| {1248 for (0..aggregate.fields.len) |field_index| {
1247 if (field_index > 0) try writer.writeByte(',');1249 if (field_index > 0) try w.writeByte(',');
1248 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {1250 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) {
1250 .none => "true",1252 .none => "true",
1251 else => "false",1253 else => "false",
1252 }),1254 }),
1253 .payload => switch (opt.val) {1255 .payload => switch (opt.val) {
1254 .none => try dg.renderUndefValue(1256 .none => try dg.renderUndefValue(
1255 writer,1257 w,
1256 ty.optionalChild(zcu),1258 ty.optionalChild(zcu),
1257 initializer_type,1259 initializer_type,
1258 ),1260 ),
1259 else => |payload| try dg.renderValue(1261 else => |payload| try dg.renderValue(
1260 writer,1262 w,
1261 Value.fromInterned(payload),1263 Value.fromInterned(payload),
1262 initializer_type,1264 initializer_type,
1263 ),1265 ),
1264 },1266 },
1265 .ptr => try writer.writeAll("NULL"),1267 .ptr => try w.writeAll("NULL"),
1266 .len => try dg.renderUndefValue(writer, .usize, initializer_type),1268 .len => try dg.renderUndefValue(w, .usize, initializer_type),
1267 else => unreachable,1269 else => unreachable,
1268 }1270 }
1269 }1271 }
1270 try writer.writeByte('}');1272 try w.writeByte('}');
1271 },1273 },
1272 },1274 },
1273 .aggregate => switch (ip.indexToKey(ty.toIntern())) {1275 .aggregate => switch (ip.indexToKey(ty.toIntern())) {
1274 .array_type, .vector_type => {1276 .array_type, .vector_type => {
1275 if (location == .FunctionArgument) {1277 if (location == .FunctionArgument) {
1276 try writer.writeByte('(');1278 try w.writeByte('(');
1277 try dg.renderCType(writer, ctype);1279 try dg.renderCType(w, ctype);
1278 try writer.writeByte(')');1280 try w.writeByte(')');
1279 }1281 }
1280 const ai = ty.arrayInfo(zcu);1282 const ai = ty.arrayInfo(zcu);
1281 if (ai.elem_type.eql(.u8, zcu)) {1283 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));
1283 try literal.start();1285 try literal.start();
1284 var index: usize = 0;1286 var index: usize = 0;
1285 while (index < ai.len) : (index += 1) {1287 while (index < ai.len) : (index += 1) {
...@@ -1296,28 +1298,28 @@ pub const DeclGen = struct {...@@ -1296,28 +1298,28 @@ pub const DeclGen = struct {
1296 }1298 }
1297 try literal.end();1299 try literal.end();
1298 } else {1300 } else {
1299 try writer.writeByte('{');1301 try w.writeByte('{');
1300 var index: usize = 0;1302 var index: usize = 0;
1301 while (index < ai.len) : (index += 1) {1303 while (index < ai.len) : (index += 1) {
1302 if (index != 0) try writer.writeByte(',');1304 if (index != 0) try w.writeByte(',');
1303 const elem_val = try val.elemValue(pt, index);1305 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);
1305 }1307 }
1306 if (ai.sentinel) |s| {1308 if (ai.sentinel) |s| {
1307 if (index != 0) try writer.writeByte(',');1309 if (index != 0) try w.writeByte(',');
1308 try dg.renderValue(writer, s, initializer_type);1310 try dg.renderValue(w, s, initializer_type);
1309 }1311 }
1310 try writer.writeByte('}');1312 try w.writeByte('}');
1311 }1313 }
1312 },1314 },
1313 .tuple_type => |tuple| {1315 .tuple_type => |tuple| {
1314 if (!location.isInitializer()) {1316 if (!location.isInitializer()) {
1315 try writer.writeByte('(');1317 try w.writeByte('(');
1316 try dg.renderCType(writer, ctype);1318 try dg.renderCType(w, ctype);
1317 try writer.writeByte(')');1319 try w.writeByte(')');
1318 }1320 }
13191321
1320 try writer.writeByte('{');1322 try w.writeByte('{');
1321 var empty = true;1323 var empty = true;
1322 for (0..tuple.types.len) |field_index| {1324 for (0..tuple.types.len) |field_index| {
1323 const comptime_val = tuple.values.get(ip)[field_index];1325 const comptime_val = tuple.values.get(ip)[field_index];
...@@ -1325,7 +1327,7 @@ pub const DeclGen = struct {...@@ -1325,7 +1327,7 @@ pub const DeclGen = struct {
1325 const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);1327 const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);
1326 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1328 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13271329
1328 if (!empty) try writer.writeByte(',');1330 if (!empty) try w.writeByte(',');
13291331
1330 const field_val = Value.fromInterned(1332 const field_val = Value.fromInterned(
1331 switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1333 switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
...@@ -1337,30 +1339,30 @@ pub const DeclGen = struct {...@@ -1337,30 +1339,30 @@ pub const DeclGen = struct {
1337 .repeated_elem => |elem| elem,1339 .repeated_elem => |elem| elem,
1338 },1340 },
1339 );1341 );
1340 try dg.renderValue(writer, field_val, initializer_type);1342 try dg.renderValue(w, field_val, initializer_type);
13411343
1342 empty = false;1344 empty = false;
1343 }1345 }
1344 try writer.writeByte('}');1346 try w.writeByte('}');
1345 },1347 },
1346 .struct_type => {1348 .struct_type => {
1347 const loaded_struct = ip.loadStructType(ty.toIntern());1349 const loaded_struct = ip.loadStructType(ty.toIntern());
1348 switch (loaded_struct.layout) {1350 switch (loaded_struct.layout) {
1349 .auto, .@"extern" => {1351 .auto, .@"extern" => {
1350 if (!location.isInitializer()) {1352 if (!location.isInitializer()) {
1351 try writer.writeByte('(');1353 try w.writeByte('(');
1352 try dg.renderCType(writer, ctype);1354 try dg.renderCType(w, ctype);
1353 try writer.writeByte(')');1355 try w.writeByte(')');
1354 }1356 }
13551357
1356 try writer.writeByte('{');1358 try w.writeByte('{');
1357 var field_it = loaded_struct.iterateRuntimeOrder(ip);1359 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1358 var need_comma = false;1360 var need_comma = false;
1359 while (field_it.next()) |field_index| {1361 while (field_it.next()) |field_index| {
1360 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);1362 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1361 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1363 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13621364
1363 if (need_comma) try writer.writeByte(',');1365 if (need_comma) try w.writeByte(',');
1364 need_comma = true;1366 need_comma = true;
1365 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1367 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
1366 .bytes => |bytes| try pt.intern(.{ .int = .{1368 .bytes => |bytes| try pt.intern(.{ .int = .{
...@@ -1370,9 +1372,9 @@ pub const DeclGen = struct {...@@ -1370,9 +1372,9 @@ pub const DeclGen = struct {
1370 .elems => |elems| elems[field_index],1372 .elems => |elems| elems[field_index],
1371 .repeated_elem => |elem| elem,1373 .repeated_elem => |elem| elem,
1372 };1374 };
1373 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);1375 try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
1374 }1376 }
1375 try writer.writeByte('}');1377 try w.writeByte('}');
1376 },1378 },
1377 .@"packed" => {1379 .@"packed" => {
1378 const int_info = ty.intInfo(zcu);1380 const int_info = ty.intInfo(zcu);
...@@ -1390,16 +1392,16 @@ pub const DeclGen = struct {...@@ -1390,16 +1392,16 @@ pub const DeclGen = struct {
1390 }1392 }
13911393
1392 if (eff_num_fields == 0) {1394 if (eff_num_fields == 0) {
1393 try writer.writeByte('(');1395 try w.writeByte('(');
1394 try dg.renderUndefValue(writer, ty, location);1396 try dg.renderUndefValue(w, ty, location);
1395 try writer.writeByte(')');1397 try w.writeByte(')');
1396 } else if (ty.bitSize(zcu) > 64) {1398 } else if (ty.bitSize(zcu) > 64) {
1397 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))1399 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
1398 var num_or = eff_num_fields - 1;1400 var num_or = eff_num_fields - 1;
1399 while (num_or > 0) : (num_or -= 1) {1401 while (num_or > 0) : (num_or -= 1) {
1400 try writer.writeAll("zig_or_");1402 try w.writeAll("zig_or_");
1401 try dg.renderTypeForBuiltinFnName(writer, ty);1403 try dg.renderTypeForBuiltinFnName(w, ty);
1402 try writer.writeByte('(');1404 try w.writeByte('(');
1403 }1405 }
14041406
1405 var eff_index: usize = 0;1407 var eff_index: usize = 0;
...@@ -1418,36 +1420,36 @@ pub const DeclGen = struct {...@@ -1418,36 +1420,36 @@ pub const DeclGen = struct {
1418 };1420 };
1419 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };1421 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
1420 if (bit_offset != 0) {1422 if (bit_offset != 0) {
1421 try writer.writeAll("zig_shl_");1423 try w.writeAll("zig_shl_");
1422 try dg.renderTypeForBuiltinFnName(writer, ty);1424 try dg.renderTypeForBuiltinFnName(w, ty);
1423 try writer.writeByte('(');1425 try w.writeByte('(');
1424 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);1426 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
1425 try writer.writeAll(", ");1427 try w.writeAll(", ");
1426 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);1428 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1427 try writer.writeByte(')');1429 try w.writeByte(')');
1428 } else {1430 } else {
1429 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);1431 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
1430 }1432 }
14311433
1432 if (needs_closing_paren) try writer.writeByte(')');1434 if (needs_closing_paren) try w.writeByte(')');
1433 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");1435 if (eff_index != eff_num_fields - 1) try w.writeAll(", ");
14341436
1435 bit_offset += field_ty.bitSize(zcu);1437 bit_offset += field_ty.bitSize(zcu);
1436 needs_closing_paren = true;1438 needs_closing_paren = true;
1437 eff_index += 1;1439 eff_index += 1;
1438 }1440 }
1439 } else {1441 } else {
1440 try writer.writeByte('(');1442 try w.writeByte('(');
1441 // a << a_off | b << b_off | c << c_off1443 // a << a_off | b << b_off | c << c_off
1442 var empty = true;1444 var empty = true;
1443 for (0..loaded_struct.field_types.len) |field_index| {1445 for (0..loaded_struct.field_types.len) |field_index| {
1444 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);1446 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1445 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1447 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
14461448
1447 if (!empty) try writer.writeAll(" | ");1449 if (!empty) try w.writeAll(" | ");
1448 try writer.writeByte('(');1450 try w.writeByte('(');
1449 try dg.renderCType(writer, ctype);1451 try dg.renderCType(w, ctype);
1450 try writer.writeByte(')');1452 try w.writeByte(')');
14511453
1452 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1454 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
1453 .bytes => |bytes| try pt.intern(.{ .int = .{1455 .bytes => |bytes| try pt.intern(.{ .int = .{
...@@ -1464,24 +1466,24 @@ pub const DeclGen = struct {...@@ -1464,24 +1466,24 @@ pub const DeclGen = struct {
1464 .{ .signedness = .unsigned, .bits = undefined };1466 .{ .signedness = .unsigned, .bits = undefined };
1465 switch (field_int_info.signedness) {1467 switch (field_int_info.signedness) {
1466 .signed => {1468 .signed => {
1467 try writer.writeByte('(');1469 try w.writeByte('(');
1468 try dg.renderValue(writer, Value.fromInterned(field_val), .Other);1470 try dg.renderValue(w, Value.fromInterned(field_val), .Other);
1469 try writer.writeAll(" & ");1471 try w.writeAll(" & ");
1470 const field_uint_ty = try pt.intType(.unsigned, field_int_info.bits);1472 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);1473 try dg.renderValue(w, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
1472 try writer.writeByte(')');1474 try w.writeByte(')');
1473 },1475 },
1474 .unsigned => try dg.renderValue(writer, Value.fromInterned(field_val), .Other),1476 .unsigned => try dg.renderValue(w, Value.fromInterned(field_val), .Other),
1475 }1477 }
1476 if (bit_offset != 0) {1478 if (bit_offset != 0) {
1477 try writer.writeAll(" << ");1479 try w.writeAll(" << ");
1478 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);1480 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1479 }1481 }
14801482
1481 bit_offset += field_ty.bitSize(zcu);1483 bit_offset += field_ty.bitSize(zcu);
1482 empty = false;1484 empty = false;
1483 }1485 }
1484 try writer.writeByte(')');1486 try w.writeByte(')');
1485 }1487 }
1486 },1488 },
1487 }1489 }
...@@ -1495,11 +1497,11 @@ pub const DeclGen = struct {...@@ -1495,11 +1497,11 @@ pub const DeclGen = struct {
1495 switch (loaded_union.flagsUnordered(ip).layout) {1497 switch (loaded_union.flagsUnordered(ip).layout) {
1496 .@"packed" => {1498 .@"packed" => {
1497 if (!location.isInitializer()) {1499 if (!location.isInitializer()) {
1498 try writer.writeByte('(');1500 try w.writeByte('(');
1499 try dg.renderType(writer, backing_ty);1501 try dg.renderType(w, backing_ty);
1500 try writer.writeByte(')');1502 try w.writeByte(')');
1501 }1503 }
1502 try dg.renderValue(writer, Value.fromInterned(un.val), location);1504 try dg.renderValue(w, Value.fromInterned(un.val), location);
1503 },1505 },
1504 .@"extern" => {1506 .@"extern" => {
1505 if (location == .StaticInitializer) {1507 if (location == .StaticInitializer) {
...@@ -1507,21 +1509,21 @@ pub const DeclGen = struct {...@@ -1507,21 +1509,21 @@ pub const DeclGen = struct {
1507 }1509 }
15081510
1509 const ptr_ty = try pt.singleConstPtrType(ty);1511 const ptr_ty = try pt.singleConstPtrType(ty);
1510 try writer.writeAll("*((");1512 try w.writeAll("*((");
1511 try dg.renderType(writer, ptr_ty);1513 try dg.renderType(w, ptr_ty);
1512 try writer.writeAll(")(");1514 try w.writeAll(")(");
1513 try dg.renderType(writer, backing_ty);1515 try dg.renderType(w, backing_ty);
1514 try writer.writeAll("){");1516 try w.writeAll("){");
1515 try dg.renderValue(writer, Value.fromInterned(un.val), location);1517 try dg.renderValue(w, Value.fromInterned(un.val), location);
1516 try writer.writeAll("})");1518 try w.writeAll("})");
1517 },1519 },
1518 else => unreachable,1520 else => unreachable,
1519 }1521 }
1520 } else {1522 } else {
1521 if (!location.isInitializer()) {1523 if (!location.isInitializer()) {
1522 try writer.writeByte('(');1524 try w.writeByte('(');
1523 try dg.renderCType(writer, ctype);1525 try dg.renderCType(w, ctype);
1524 try writer.writeByte(')');1526 try w.writeByte(')');
1525 }1527 }
15261528
1527 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;1529 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
...@@ -1530,57 +1532,57 @@ pub const DeclGen = struct {...@@ -1530,57 +1532,57 @@ pub const DeclGen = struct {
1530 if (loaded_union.flagsUnordered(ip).layout == .@"packed") {1532 if (loaded_union.flagsUnordered(ip).layout == .@"packed") {
1531 if (field_ty.hasRuntimeBits(zcu)) {1533 if (field_ty.hasRuntimeBits(zcu)) {
1532 if (field_ty.isPtrAtRuntime(zcu)) {1534 if (field_ty.isPtrAtRuntime(zcu)) {
1533 try writer.writeByte('(');1535 try w.writeByte('(');
1534 try dg.renderCType(writer, ctype);1536 try dg.renderCType(w, ctype);
1535 try writer.writeByte(')');1537 try w.writeByte(')');
1536 } else if (field_ty.zigTypeTag(zcu) == .float) {1538 } else if (field_ty.zigTypeTag(zcu) == .float) {
1537 try writer.writeByte('(');1539 try w.writeByte('(');
1538 try dg.renderCType(writer, ctype);1540 try dg.renderCType(w, ctype);
1539 try writer.writeByte(')');1541 try w.writeByte(')');
1540 }1542 }
1541 try dg.renderValue(writer, Value.fromInterned(un.val), location);1543 try dg.renderValue(w, Value.fromInterned(un.val), location);
1542 } else try writer.writeByte('0');1544 } else try w.writeByte('0');
1543 return;1545 return;
1544 }1546 }
15451547
1546 const has_tag = loaded_union.hasTag(ip);1548 const has_tag = loaded_union.hasTag(ip);
1547 if (has_tag) try writer.writeByte('{');1549 if (has_tag) try w.writeByte('{');
1548 const aggregate = ctype.info(ctype_pool).aggregate;1550 const aggregate = ctype.info(ctype_pool).aggregate;
1549 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {1551 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(',');
1551 switch (if (has_tag)1553 switch (if (has_tag)
1552 aggregate.fields.at(outer_field_index, ctype_pool).name.index1554 aggregate.fields.at(outer_field_index, ctype_pool).name.index
1553 else1555 else
1554 .payload) {1556 .payload) {
1555 .tag => try dg.renderValue(1557 .tag => try dg.renderValue(
1556 writer,1558 w,
1557 Value.fromInterned(un.tag),1559 Value.fromInterned(un.tag),
1558 initializer_type,1560 initializer_type,
1559 ),1561 ),
1560 .payload => {1562 .payload => {
1561 try writer.writeByte('{');1563 try w.writeByte('{');
1562 if (field_ty.hasRuntimeBits(zcu)) {1564 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))});
1564 try dg.renderValue(1566 try dg.renderValue(
1565 writer,1567 w,
1566 Value.fromInterned(un.val),1568 Value.fromInterned(un.val),
1567 initializer_type,1569 initializer_type,
1568 );1570 );
1569 try writer.writeByte(' ');1571 try w.writeByte(' ');
1570 } else for (0..loaded_union.field_types.len) |inner_field_index| {1572 } else for (0..loaded_union.field_types.len) |inner_field_index| {
1571 const inner_field_ty: Type = .fromInterned(1573 const inner_field_ty: Type = .fromInterned(
1572 loaded_union.field_types.get(ip)[inner_field_index],1574 loaded_union.field_types.get(ip)[inner_field_index],
1573 );1575 );
1574 if (!inner_field_ty.hasRuntimeBits(zcu)) continue;1576 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);
1576 break;1578 break;
1577 }1579 }
1578 try writer.writeByte('}');1580 try w.writeByte('}');
1579 },1581 },
1580 else => unreachable,1582 else => unreachable,
1581 }1583 }
1582 }1584 }
1583 if (has_tag) try writer.writeByte('}');1585 if (has_tag) try w.writeByte('}');
1584 }1586 }
1585 },1587 },
1586 }1588 }
...@@ -2999,18 +3001,20 @@ pub fn generate(...@@ -2999,18 +3001,20 @@ pub fn generate(
2999 .pass = .{ .nav = func.owner_nav },3001 .pass = .{ .nav = func.owner_nav },
3000 .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,3002 .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
3001 .expected_block = null,3003 .expected_block = null,
3002 .fwd_decl = .init(gpa),3004 .fwd_decl = undefined,
3003 .ctype_pool = .empty,3005 .ctype_pool = .empty,
3004 .scratch = .empty,3006 .scratch = .empty,
3005 .uavs = .empty,3007 .uavs = .empty,
3006 },3008 },
3007 .code = .init(gpa),3009 .code_header = undefined,
3008 .indent_writer = undefined, // set later so we can get a pointer to object.code3010 .code = undefined,
3011 .indent_counter = 0,
3009 },3012 },
3010 .lazy_fns = .empty,3013 .lazy_fns = .empty,
3011 };3014 };
3012 defer {3015 defer {
3013 function.object.code.deinit();3016 function.object.code_header.init(gpa);
3017 function.object.code.init(gpa);
3014 function.object.dg.fwd_decl.deinit();3018 function.object.dg.fwd_decl.deinit();
3015 function.object.dg.ctype_pool.deinit(gpa);3019 function.object.dg.ctype_pool.deinit(gpa);
3016 function.object.dg.scratch.deinit(gpa);3020 function.object.dg.scratch.deinit(gpa);
...@@ -3018,7 +3022,9 @@ pub fn generate(...@@ -3018,7 +3022,9 @@ pub fn generate(
3018 function.deinit();3022 function.deinit();
3019 }3023 }
3020 try function.object.dg.ctype_pool.init(gpa);3024 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
3023 genFunc(&function) catch |err| switch (err) {3029 genFunc(&function) catch |err| switch (err) {
3024 error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),3030 error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),
...@@ -3034,6 +3040,7 @@ pub fn generate(...@@ -3034,6 +3040,7 @@ pub fn generate(
3034 };3040 };
3035 errdefer mir.deinit(gpa);3041 errdefer mir.deinit(gpa);
3036 mir.uavs = function.object.dg.uavs.move();3042 mir.uavs = function.object.dg.uavs.move();
3043 mir.code_header = try function.object.code_header.toOwnedSlice();
3037 mir.code = try function.object.code.toOwnedSlice();3044 mir.code = try function.object.code.toOwnedSlice();
3038 mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();3045 mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();
3039 mir.ctype_pool = function.object.dg.ctype_pool.move();3046 mir.ctype_pool = function.object.dg.ctype_pool.move();
...@@ -3041,7 +3048,7 @@ pub fn generate(...@@ -3041,7 +3048,7 @@ pub fn generate(
3041 return mir;3048 return mir;
3042}3049}
30433050
3044fn genFunc(f: *Function) !void {3051pub fn genFunc(f: *Function) Error!void {
3045 const tracy = trace(@src());3052 const tracy = trace(@src());
3046 defer tracy.end();3053 defer tracy.end();
30473054
...@@ -4033,7 +4040,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -4033,7 +4040,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
4033 try f.writeCValueDeref(w, ret_val)4040 try f.writeCValueDeref(w, ret_val)
4034 else4041 else
4035 try f.writeCValue(w, ret_val, .Other);4042 try f.writeCValue(w, ret_val, .Other);
4036 try w.writeAll(";\n");4043 try w.write(";\n");
4037 if (is_array) {4044 if (is_array) {
4038 try freeLocal(f, inst, ret_val.new_local, null);4045 try freeLocal(f, inst, ret_val.new_local, null);
4039 }4046 }
...@@ -4347,7 +4354,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:...@@ -4347,7 +4354,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
4347 try f.writeCValue(w, rhs, .FunctionArgument);4354 try f.writeCValue(w, rhs, .FunctionArgument);
4348 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);4355 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
4349 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);4356 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
4350 try w.writeAll(");\n");4357 try w.writeAll(");");
4358 try f.object.newline();
4351 try v.end(f, inst, w);4359 try v.end(f, inst, w);
43524360
4353 return local;4361 return local;
...@@ -4884,8 +4892,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4884,8 +4892,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4884 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4892 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4885 const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);4893 const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
4886 const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);4894 const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
4887 const writer = f.object.writer();4895 const w = &f.object.code.buffered_writer;
4888 try writer.print("/* inline:{f} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)});4896 try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4897 try f.object.newline();
4889 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));4898 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));
4890}4899}
48914900
...@@ -7415,30 +7424,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7415,30 +7424,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
7415 const inst_ty = unwrapped.result_ty;7424 const inst_ty = unwrapped.result_ty;
7416 const elem_ty = inst_ty.childType(zcu);7425 const elem_ty = inst_ty.childType(zcu);
74177426
7418 const writer = &f.object.code.buffered_writer;7427 const w = &f.object.code.buffered_writer;
7419 const local = try f.allocLocal(inst, inst_ty);7428 const local = try f.allocLocal(inst, inst_ty);
7420 try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands7429 try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands
7421 for (mask, 0..) |mask_elem, out_idx| {7430 for (mask, 0..) |mask_elem, out_idx| {
7422 try f.writeCValue(writer, local, .Other);7431 try f.writeCValue(w, local, .Other);
7423 try writer.writeByte('[');7432 try w.writeByte('[');
7424 try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other);7433 try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
7425 try writer.writeAll("] = ");7434 try w.writeAll("] = ");
7426 switch (mask_elem.unwrap()) {7435 switch (mask_elem.unwrap()) {
7427 .a_elem => |src_idx| {7436 .a_elem => |src_idx| {
7428 try f.writeCValue(writer, operand_a, .Other);7437 try f.writeCValue(w, operand_a, .Other);
7429 try writer.writeByte('[');7438 try w.writeByte('[');
7430 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);7439 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7431 try writer.writeByte(']');7440 try w.writeByte(']');
7432 },7441 },
7433 .b_elem => |src_idx| {7442 .b_elem => |src_idx| {
7434 try f.writeCValue(writer, operand_b, .Other);7443 try f.writeCValue(w, operand_b, .Other);
7435 try writer.writeByte('[');7444 try w.writeByte('[');
7436 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);7445 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7437 try writer.writeByte(']');7446 try w.writeByte(']');
7438 },7447 },
7439 .undef => try f.object.dg.renderUndefValue(writer, elem_ty, .Other),7448 .undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other),
7440 }7449 }
7441 try writer.writeAll(";\n");7450 try w.writeByte(';');
7451 try f.object.newline();
7442 }7452 }
74437453
7444 return local;7454 return local;
...@@ -7889,12 +7899,13 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7889,12 +7899,13 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
78897899
7890fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {7900fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7891 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;7901 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;
7893 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));7903 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
7894 try f.writeCValue(writer, local, .Other);7904 try f.writeCValue(w, local, .Other);
7895 try writer.writeAll(" = ");7905 try w.writeAll(" = ");
7896 try f.object.dg.renderNav(writer, ty_nav.nav, .Other);7906 try f.object.dg.renderNav(w, ty_nav.nav, .Other);
7897 try writer.writeAll(";\n");7907 try w.writeByte(';');
7908 try f.object.newline();
7898 return local;7909 return local;
7899}7910}
79007911
...@@ -8480,19 +8491,19 @@ const Assignment = struct {...@@ -8480,19 +8491,19 @@ const Assignment = struct {
8480const Vectorize = struct {8491const Vectorize = struct {
8481 index: CValue = .none,8492 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 {
8484 const pt = f.object.dg.pt;8495 const pt = f.object.dg.pt;
8485 const zcu = pt.zcu;8496 const zcu = pt.zcu;
8486 return if (ty.zigTypeTag(zcu) == .vector) index: {8497 return if (ty.zigTypeTag(zcu) == .vector) index: {
8487 const local = try f.allocLocal(inst, .usize);8498 const local = try f.allocLocal(inst, .usize);
84888499
8489 try writer.writeAll("for (");8500 try w.writeAll("for (");
8490 try f.writeCValue(writer, local, .Other);8501 try f.writeCValue(w, local, .Other);
8491 try writer.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});8502 try w.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});
8492 try f.writeCValue(writer, local, .Other);8503 try f.writeCValue(w, local, .Other);
8493 try writer.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});8504 try w.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
8494 try f.writeCValue(writer, local, .Other);8505 try f.writeCValue(w, local, .Other);
8495 try writer.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});8506 try w.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
8496 f.object.indent();8507 f.object.indent();
8497 try f.object.newline();8508 try f.object.newline();
84988509
src/link/C.zig+175-158
...@@ -25,34 +25,34 @@ base: link.File,...@@ -25,34 +25,34 @@ base: link.File,
25/// This linker backend does not try to incrementally link output C source code.25/// This linker backend does not try to incrementally link output C source code.
26/// Instead, it tracks all declarations in this table, and iterates over it26/// Instead, it tracks all declarations in this table, and iterates over it
27/// in the flush function, stitching pre-rendered pieces of C code together.27/// 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),
29/// All the string bytes of rendered C code, all squished into one array.29/// All the string bytes of rendered C code, all squished into one array.
30/// While in progress, a separate buffer is used, and then when finished, the30/// While in progress, a separate buffer is used, and then when finished, the
31/// buffer is copied into this one.31/// buffer is copied into this one.
32string_bytes: std.ArrayListUnmanaged(u8) = .empty,32string_bytes: std.ArrayListUnmanaged(u8),
33/// Tracks all the anonymous decls that are used by all the decls so they can33/// Tracks all the anonymous decls that are used by all the decls so they can
34/// be rendered during flush().34/// be rendered during flush().
35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock) = .empty,35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock),
36/// Sparse set of uavs that are overaligned. Underaligned anon decls are36/// Sparse set of uavs that are overaligned. Underaligned anon decls are
37/// lowered the same as ABI-aligned anon decls. The keys here are a subset of37/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
38/// the keys of `uavs`.38/// 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,41exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock),
42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .empty,42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock),
4343
44/// Optimization, `updateDecl` reuses this buffer rather than creating a new44/// Optimization, `updateDecl` reuses this buffer rather than creating a new
45/// one with every call.45/// one with every call.
46fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,46fwd_decl_buf: []u8,
47/// Optimization, `updateDecl` reuses this buffer rather than creating a new47/// Optimization, `updateDecl` reuses this buffer rather than creating a new
48/// one with every call.48/// one with every call.
49code_buf: std.ArrayListUnmanaged(u8) = .empty,49code_header_buf: []u8,
50/// Optimization, `flush` reuses this buffer rather than creating a new50/// Optimization, `updateDecl` reuses this buffer rather than creating a new
51/// one with every call.51/// one with every call.
52lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,52code_buf: []u8,
53/// Optimization, `flush` reuses this buffer rather than creating a new53/// Optimization, `flush` reuses this buffer rather than creating a new
54/// one with every call.54/// one with every call.
55lazy_code_buf: std.ArrayListUnmanaged(u8) = .empty,55scratch_buf: []u32,
5656
57/// A reference into `string_bytes`.57/// A reference into `string_bytes`.
58const String = extern struct {58const String = extern struct {
...@@ -67,11 +67,11 @@ const String = extern struct {...@@ -67,11 +67,11 @@ const String = extern struct {
6767
68/// Per-declaration data.68/// Per-declaration data.
69pub const AvBlock = struct {69pub const AvBlock = struct {
70 code: String = String.empty,70 fwd_decl: String = .empty,
71 fwd_decl: String = String.empty,71 code: String = .empty,
72 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate72 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
73 /// over each `Decl` and generate the definition for each used `CType` once.73 /// 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,
75 /// May contain string references to ctype_pool75 /// May contain string references to ctype_pool
76 lazy_fns: codegen.LazyFnMap = .{},76 lazy_fns: codegen.LazyFnMap = .{},
7777
...@@ -84,20 +84,21 @@ pub const AvBlock = struct {...@@ -84,20 +84,21 @@ pub const AvBlock = struct {
8484
85/// Per-exported-symbol data.85/// Per-exported-symbol data.
86pub const ExportedBlock = struct {86pub const ExportedBlock = struct {
87 fwd_decl: String = String.empty,87 fwd_decl: String = .empty,
88};88};
8989
90pub fn getString(this: C, s: String) []const u8 {90pub fn getString(this: C, s: String) []const u8 {
91 return this.string_bytes.items[s.start..][0..s.len];91 return this.string_bytes.items[s.start..][0..s.len];
92}92}
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 {
95 const comp = this.base.comp;95 const comp = this.base.comp;
96 const gpa = comp.gpa;96 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());
98 return .{99 return .{
99 .start = @intCast(this.string_bytes.items.len - s.len),100 .start = @intCast(start),
100 .len = @intCast(s.len),101 .len = @intCast(this.string_bytes.items.len - start),
101 };102 };
102}103}
103104
...@@ -147,6 +148,16 @@ pub fn createEmpty(...@@ -147,6 +148,16 @@ pub fn createEmpty(
147 .file = file,148 .file = file,
148 .build_id = options.build_id,149 .build_id = options.build_id,
149 },150 },
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 = &.{},
150 };161 };
151162
152 return c_file;163 return c_file;
...@@ -170,10 +181,10 @@ pub fn deinit(self: *C) void {...@@ -170,10 +181,10 @@ pub fn deinit(self: *C) void {
170 self.exported_uavs.deinit(gpa);181 self.exported_uavs.deinit(gpa);
171182
172 self.string_bytes.deinit(gpa);183 self.string_bytes.deinit(gpa);
173 self.fwd_decl_buf.deinit(gpa);184 gpa.free(self.fwd_decl_buf);
174 self.code_buf.deinit(gpa);185 gpa.free(self.code_header_buf);
175 self.lazy_fwd_decl_buf.deinit(gpa);186 gpa.free(self.code_buf);
176 self.lazy_code_buf.deinit(gpa);187 gpa.free(self.scratch_buf);
177}188}
178189
179pub fn updateFunc(190pub fn updateFunc(
...@@ -194,20 +205,15 @@ pub fn updateFunc(...@@ -194,20 +205,15 @@ pub fn updateFunc(
194 .ctype_pool = mir.c.ctype_pool.move(),205 .ctype_pool = mir.c.ctype_pool.move(),
195 .lazy_fns = mir.c.lazy_fns.move(),206 .lazy_fns = mir.c.lazy_fns.move(),
196 };207 };
197 gop.value_ptr.code = try self.addString(mir.c.code);208 gop.value_ptr.fwd_decl = try self.addString(&.{&function.object.dg.fwd_decl});
198 gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl);209 gop.value_ptr.code = try self.addString(&.{ &function.object.code_header, &function.object.code });
199 try self.addUavsFromCodegen(&mir.c.uavs);210 try self.addUavsFromCodegen(&mir.c.uavs);
200}211}
201212
202fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {213fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) link.File.FlushError!void {
203 const gpa = self.base.comp.gpa;214 const gpa = self.base.comp.gpa;
204 const uav = self.uavs.keys()[i];215 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
211 var object: codegen.Object = .{217 var object: codegen.Object = .{
212 .dg = .{218 .dg = .{
213 .gpa = gpa,219 .gpa = gpa,
...@@ -217,21 +223,24 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {...@@ -217,21 +223,24 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
217 .pass = .{ .uav = uav },223 .pass = .{ .uav = uav },
218 .is_naked_fn = false,224 .is_naked_fn = false,
219 .expected_block = null,225 .expected_block = null,
220 .fwd_decl = fwd_decl.toManaged(gpa),226 .fwd_decl = undefined,
221 .ctype_pool = codegen.CType.Pool.empty,227 .ctype_pool = .empty,
222 .scratch = .{},228 .scratch = .initBuffer(self.scratch_buf),
223 .uavs = .empty,229 .uavs = .empty,
224 },230 },
225 .code = code.toManaged(gpa),231 .code_header = undefined,
226 .indent_writer = undefined, // set later so we can get a pointer to object.code232 .code = undefined,
233 .indent_counter = 0,
227 };234 };
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);
229 defer {237 defer {
230 object.dg.uavs.deinit(gpa);238 object.dg.uavs.deinit(gpa);
231 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
232 object.dg.ctype_pool.deinit(object.dg.gpa);239 object.dg.ctype_pool.deinit(object.dg.gpa);
233 object.dg.scratch.deinit(gpa);240
234 code.* = object.code.moveToUnmanaged();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();
235 }244 }
236 try object.dg.ctype_pool.init(gpa);245 try object.dg.ctype_pool.init(gpa);
237246
...@@ -243,15 +252,15 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {...@@ -243,15 +252,15 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
243 //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);252 //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
244 //return;253 //return;
245 },254 },
246 else => |e| return e,255 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
247 };256 };
248257
249 try self.addUavsFromCodegen(&object.dg.uavs);258 try self.addUavsFromCodegen(&object.dg.uavs);
250259
251 object.dg.ctype_pool.freeUnusedCapacity(gpa);260 object.dg.ctype_pool.freeUnusedCapacity(gpa);
252 self.uavs.values()[i] = .{261 self.uavs.values()[i] = .{
253 .code = try self.addString(object.code.items),262 .fwd_decl = try self.addString(&.{&object.dg.fwd_decl}),
254 .fwd_decl = try self.addString(object.dg.fwd_decl.items),263 .code = try self.addString(&.{&object.code}),
255 .ctype_pool = object.dg.ctype_pool.move(),264 .ctype_pool = object.dg.ctype_pool.move(),
256 };265 };
257}266}
...@@ -277,12 +286,8 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l...@@ -277,12 +286,8 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
277 errdefer _ = self.navs.pop();286 errdefer _ = self.navs.pop();
278 if (!gop.found_existing) gop.value_ptr.* = .{};287 if (!gop.found_existing) gop.value_ptr.* = .{};
279 const ctype_pool = &gop.value_ptr.ctype_pool;288 const ctype_pool = &gop.value_ptr.ctype_pool;
280 const fwd_decl = &self.fwd_decl_buf;
281 const code = &self.code_buf;
282 try ctype_pool.init(gpa);289 try ctype_pool.init(gpa);
283 ctype_pool.clearRetainingCapacity();290 ctype_pool.clearRetainingCapacity();
284 fwd_decl.clearRetainingCapacity();
285 code.clearRetainingCapacity();
286291
287 var object: codegen.Object = .{292 var object: codegen.Object = .{
288 .dg = .{293 .dg = .{
...@@ -293,22 +298,25 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l...@@ -293,22 +298,25 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
293 .pass = .{ .nav = nav_index },298 .pass = .{ .nav = nav_index },
294 .is_naked_fn = false,299 .is_naked_fn = false,
295 .expected_block = null,300 .expected_block = null,
296 .fwd_decl = fwd_decl.toManaged(gpa),301 .fwd_decl = undefined,
297 .ctype_pool = ctype_pool.*,302 .ctype_pool = ctype_pool.*,
298 .scratch = .{},303 .scratch = .initBuffer(self.scratch_buf),
299 .uavs = .empty,304 .uavs = .empty,
300 },305 },
301 .code = code.toManaged(gpa),306 .code_header = undefined,
302 .indent_writer = undefined, // set later so we can get a pointer to object.code307 .code = undefined,
308 .indent_counter = 0,
303 };309 };
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);
305 defer {312 defer {
306 object.dg.uavs.deinit(gpa);313 object.dg.uavs.deinit(gpa);
307 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
308 ctype_pool.* = object.dg.ctype_pool.move();314 ctype_pool.* = object.dg.ctype_pool.move();
309 ctype_pool.freeUnusedCapacity(gpa);315 ctype_pool.freeUnusedCapacity(gpa);
310 object.dg.scratch.deinit(gpa);316
311 code.* = object.code.moveToUnmanaged();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();
312 }320 }
313321
314 codegen.genDecl(&object) catch |err| switch (err) {322 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...@@ -316,10 +324,10 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
316 error.CodegenFail => return,324 error.CodegenFail => return,
317 error.OutOfMemory => |e| return e,325 error.OutOfMemory => |e| return e,
318 },326 },
319 else => |e| return e,327 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
320 };328 };
321 gop.value_ptr.code = try self.addString(object.code.items);329 gop.value_ptr.fwd_decl = try self.addString(&.{&object.dg.fwd_decl});
322 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);330 gop.value_ptr.code = try self.addString(&.{&object.code});
323 try self.addUavsFromCodegen(&object.dg.uavs);331 try self.addUavsFromCodegen(&object.dg.uavs);
324}332}
325333
...@@ -331,19 +339,14 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn...@@ -331,19 +339,14 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn
331 _ = ti_id;339 _ = ti_id;
332}340}
333341
334fn abiDefines(self: *C, target: *const std.Target) !std.ArrayList(u8) {342fn abiDefines(bw: *std.io.BufferedWriter, target: std.Target) !void {
335 const gpa = self.base.comp.gpa;
336 var defines = std.ArrayList(u8).init(gpa);
337 errdefer defines.deinit();
338 const writer = defines.writer();
339 switch (target.abi) {343 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"),
341 else => {},345 else => {},
342 }346 }
343 try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{347 try bw.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
344 target.cMaxIntAlignment(),348 target.cMaxIntAlignment(),
345 });349 });
346 return defines;
347}350}
348351
349pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {352pub 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...@@ -374,37 +377,49 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
374 // emit-h is in `flushEmitH` below.377 // emit-h is in `flushEmitH` below.
375378
376 var f: Flush = .{379 var f: Flush = .{
377 .ctype_pool = codegen.CType.Pool.empty,380 .ctype_pool = .empty,
378 .lazy_ctype_pool = codegen.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,
379 };391 };
380 defer f.deinit(gpa);392 defer f.deinit(gpa);
381393
382 const abi_defines = try self.abiDefines(zcu.getTarget());394 var abi_defines_aw: std.io.AllocatingWriter = undefined;
383 defer abi_defines.deinit();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
385 // Covers defines, zig.h, ctypes, asm, lazy fwd.401 // Covers defines, zig.h, ctypes, asm, lazy fwd.
386 try f.all_buffers.ensureUnusedCapacity(gpa, 5);402 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
387403
388 f.appendBufAssumeCapacity(abi_defines.items);404 f.appendBufAssumeCapacity(abi_defines_aw.getWritten());
389 f.appendBufAssumeCapacity(zig_h);405 f.appendBufAssumeCapacity(zig_h);
390406
391 const ctypes_index = f.all_buffers.items.len;407 const ctypes_index = f.all_buffers.items.len;
392 f.all_buffers.items.len += 1;408 f.all_buffers.items.len += 1;
393409
394 {410 var asm_aw: std.io.AllocatingWriter = undefined;
395 var asm_buf = f.asm_buf.toManaged(gpa);411 asm_aw.init(gpa);
396 defer f.asm_buf = asm_buf.moveToUnmanaged();412 defer asm_aw.deinit();
397 try codegen.genGlobalAsm(zcu, asm_buf.writer());413 codegen.genGlobalAsm(zcu, &asm_aw.buffered_writer) catch |err| switch (err) {
398 f.appendBufAssumeCapacity(asm_buf.items);414 error.WriteFailed => return error.OutOfMemory,
399 }415 };
416 f.appendBufAssumeCapacity(asm_aw.getWritten());
400417
401 const lazy_index = f.all_buffers.items.len;418 const lazy_index = f.all_buffers.items.len;
402 f.all_buffers.items.len += 1;419 f.all_buffers.items.len += 1;
403420
404 self.lazy_fwd_decl_buf.clearRetainingCapacity();
405 self.lazy_code_buf.clearRetainingCapacity();
406 try f.lazy_ctype_pool.init(gpa);421 try f.lazy_ctype_pool.init(gpa);
407 try self.flushErrDecls(pt, &f.lazy_ctype_pool);422 try self.flushErrDecls(pt, &f);
408423
409 // Unlike other backends, the .c code we are emitting has order-dependent decls.424 // Unlike other backends, the .c code we are emitting has order-dependent decls.
410 // `CType`s, forward decls, and non-functions first.425 // `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...@@ -462,22 +477,15 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
462 }477 }
463 }478 }
464479
465 f.all_buffers.items[ctypes_index] = .{480 f.all_buffers.items[ctypes_index] = f.ctypes.items;
466 .base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",481 f.file_size += f.ctypes.items.len;
467 .len = f.ctypes_buf.items.len,
468 };
469 f.file_size += f.ctypes_buf.items.len;
470482
471 const lazy_fwd_decl_len = self.lazy_fwd_decl_buf.items.len;483 f.all_buffers.items[lazy_index] = f.lazy_fwd_decl.items;
472 f.all_buffers.items[lazy_index] = .{484 f.file_size += f.lazy_fwd_decl.items.len;
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;
477485
478 // Now the code.486 // Now the code.
479 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);487 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);
481 for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(489 for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
482 if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {490 if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
483 .@"extern" => .zig_extern,491 .@"extern" => .zig_extern,
...@@ -493,31 +501,35 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P...@@ -493,31 +501,35 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
493501
494 const file = self.base.file.?;502 const file = self.base.file.?;
495 file.setEndPos(f.file_size) catch |err| return diags.fail("failed to allocate file: {s}", .{@errorName(err)});503 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}", .{504 var fw = file.writer();
497 self.base.emit, @errorName(err),505 var bw = fw.interface().unbuffered();
498 });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 };
499}511}
500512
501const Flush = struct {513const Flush = struct {
502 ctype_pool: codegen.CType.Pool,514 ctype_pool: codegen.CType.Pool,
503 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .empty,515 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType),
504 ctypes_buf: std.ArrayListUnmanaged(u8) = .empty,516 ctypes: std.ArrayListUnmanaged(u8),
505517
506 lazy_ctype_pool: codegen.CType.Pool,518 lazy_ctype_pool: codegen.CType.Pool,
507 lazy_fns: LazyFns = .{},519 lazy_fns: LazyFns,
508520 lazy_fwd_decl: std.ArrayListUnmanaged(u8),
509 asm_buf: std.ArrayListUnmanaged(u8) = .empty,521 lazy_code: std.ArrayListUnmanaged(u8),
510522
511 /// We collect a list of buffers to write, and write them all at once with pwritev 😎523 /// 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),
513 /// Keeps track of the total bytes of `all_buffers`.525 /// Keeps track of the total bytes of `all_buffers`.
514 file_size: u64 = 0,526 file_size: u64,
515527
516 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);528 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
517529
518 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {530 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
519 if (buf.len == 0) return;531 if (buf.len == 0) return;
520 f.all_buffers.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });532 f.all_buffers.appendAssumeCapacity(buf);
521 f.file_size += buf.len;533 f.file_size += buf.len;
522 }534 }
523535
...@@ -532,14 +544,15 @@ const Flush = struct {...@@ -532,14 +544,15 @@ const Flush = struct {
532 }544 }
533545
534 fn deinit(f: *Flush, gpa: Allocator) void {546 fn deinit(f: *Flush, gpa: Allocator) void {
535 f.all_buffers.deinit(gpa);547 f.ctype_pool.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);
540 assert(f.ctype_global_from_decl_map.items.len == 0);548 assert(f.ctype_global_from_decl_map.items.len == 0);
541 f.ctype_global_from_decl_map.deinit(gpa);549 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);
543 }556 }
544};557};
545558
...@@ -562,9 +575,9 @@ fn flushCTypes(...@@ -562,9 +575,9 @@ fn flushCTypes(
562 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);575 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
563 defer global_from_decl_map.clearRetainingCapacity();576 defer global_from_decl_map.clearRetainingCapacity();
564577
565 var ctypes_buf = f.ctypes_buf.toManaged(gpa);578 var ctypes_aw: std.io.AllocatingWriter = undefined;
566 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();579 const ctypes_bw = ctypes_aw.fromArrayList(gpa, &f.ctypes);
567 const writer = ctypes_buf.writer();580 defer f.ctypes = ctypes_aw.toArrayList();
568581
569 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {582 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
570 const PoolAdapter = struct {583 const PoolAdapter = struct {
...@@ -591,26 +604,25 @@ fn flushCTypes(...@@ -591,26 +604,25 @@ fn flushCTypes(
591 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },604 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
592 );605 );
593 global_from_decl_map.appendAssumeCapacity(global_ctype);606 global_from_decl_map.appendAssumeCapacity(global_ctype);
594 try codegen.genTypeDecl(607 codegen.genTypeDecl(
595 zcu,608 zcu,
596 writer,609 ctypes_bw,
597 global_ctype_pool,610 global_ctype_pool,
598 global_ctype,611 global_ctype,
599 pass,612 pass,
600 decl_ctype_pool,613 decl_ctype_pool,
601 decl_ctype,614 decl_ctype,
602 found_existing,615 found_existing,
603 );616 ) catch |err| switch (err) {
617 error.WriteFailed => return error.OutOfMemory,
618 };
604 }619 }
605}620}
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 {
608 const gpa = self.base.comp.gpa;623 const gpa = self.base.comp.gpa;
609624
610 const fwd_decl = &self.lazy_fwd_decl_buf;625 var object: codegen.Object = .{
611 const code = &self.lazy_code_buf;
612
613 var object = codegen.Object{
614 .dg = .{626 .dg = .{
615 .gpa = gpa,627 .gpa = gpa,
616 .pt = pt,628 .pt = pt,
...@@ -619,27 +631,30 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F...@@ -619,27 +631,30 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F
619 .pass = .flush,631 .pass = .flush,
620 .is_naked_fn = false,632 .is_naked_fn = false,
621 .expected_block = null,633 .expected_block = null,
622 .fwd_decl = fwd_decl.toManaged(gpa),634 .fwd_decl = undefined,
623 .ctype_pool = ctype_pool.*,635 .ctype_pool = f.lazy_ctype_pool,
624 .scratch = .{},636 .scratch = .initBuffer(self.scratch_buf),
625 .uavs = .empty,637 .uavs = .empty,
626 },638 },
627 .code = code.toManaged(gpa),639 .code_header = undefined,
628 .indent_writer = undefined, // set later so we can get a pointer to object.code640 .code = undefined,
641 .indent_counter = 0,
629 };642 };
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);
631 defer {645 defer {
632 object.dg.uavs.deinit(gpa);646 object.dg.uavs.deinit(gpa);
633 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();647 f.lazy_ctype_pool = object.dg.ctype_pool.move();
634 ctype_pool.* = object.dg.ctype_pool.move();648 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
635 ctype_pool.freeUnusedCapacity(gpa);649
636 object.dg.scratch.deinit(gpa);650 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
637 code.* = object.code.moveToUnmanaged();651 f.lazy_code = object.code.toArrayList();
652 self.scratch_buf = object.dg.scratch.allocatedSlice();
638 }653 }
639654
640 codegen.genErrDecls(&object) catch |err| switch (err) {655 codegen.genErrDecls(&object) catch |err| switch (err) {
641 error.AnalysisFail => unreachable,656 error.AnalysisFail => unreachable,
642 else => |e| return e,657 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
643 };658 };
644659
645 try self.addUavsFromCodegen(&object.dg.uavs);660 try self.addUavsFromCodegen(&object.dg.uavs);
...@@ -649,16 +664,13 @@ fn flushLazyFn(...@@ -649,16 +664,13 @@ fn flushLazyFn(
649 self: *C,664 self: *C,
650 pt: Zcu.PerThread,665 pt: Zcu.PerThread,
651 mod: *Module,666 mod: *Module,
652 ctype_pool: *codegen.CType.Pool,667 f: *Flush,
653 lazy_ctype_pool: *const codegen.CType.Pool,668 lazy_ctype_pool: *const codegen.CType.Pool,
654 lazy_fn: codegen.LazyFnMap.Entry,669 lazy_fn: codegen.LazyFnMap.Entry,
655) FlushDeclError!void {670) FlushDeclError!void {
656 const gpa = self.base.comp.gpa;671 const gpa = self.base.comp.gpa;
657672
658 const fwd_decl = &self.lazy_fwd_decl_buf;673 var object: codegen.Object = .{
659 const code = &self.lazy_code_buf;
660
661 var object = codegen.Object{
662 .dg = .{674 .dg = .{
663 .gpa = gpa,675 .gpa = gpa,
664 .pt = pt,676 .pt = pt,
...@@ -667,29 +679,32 @@ fn flushLazyFn(...@@ -667,29 +679,32 @@ fn flushLazyFn(
667 .pass = .flush,679 .pass = .flush,
668 .is_naked_fn = false,680 .is_naked_fn = false,
669 .expected_block = null,681 .expected_block = null,
670 .fwd_decl = fwd_decl.toManaged(gpa),682 .fwd_decl = undefined,
671 .ctype_pool = ctype_pool.*,683 .ctype_pool = f.lazy_ctype_pool,
672 .scratch = .{},684 .scratch = .initBuffer(self.scratch_buf),
673 .uavs = .empty,685 .uavs = .empty,
674 },686 },
675 .code = code.toManaged(gpa),687 .code_header = undefined,
676 .indent_writer = undefined, // set later so we can get a pointer to object.code688 .code = undefined,
689 .indent_counter = 0,
677 };690 };
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);
679 defer {693 defer {
680 // If this assert trips just handle the anon_decl_deps the same as694 // If this assert trips just handle the anon_decl_deps the same as
681 // `updateFunc()` does.695 // `updateFunc()` does.
682 assert(object.dg.uavs.count() == 0);696 assert(object.dg.uavs.count() == 0);
683 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();697 f.lazy_ctype_pool = object.dg.ctype_pool.move();
684 ctype_pool.* = object.dg.ctype_pool.move();698 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
685 ctype_pool.freeUnusedCapacity(gpa);699
686 object.dg.scratch.deinit(gpa);700 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
687 code.* = object.code.moveToUnmanaged();701 f.lazy_code = object.code.toArrayList();
702 self.scratch_buf = object.dg.scratch.allocatedSlice();
688 }703 }
689704
690 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {705 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
691 error.AnalysisFail => unreachable,706 error.AnalysisFail => unreachable,
692 else => |e| return e,707 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
693 };708 };
694}709}
695710
...@@ -709,7 +724,7 @@ fn flushLazyFns(...@@ -709,7 +724,7 @@ fn flushLazyFns(
709 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);724 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
710 if (gop.found_existing) continue;725 if (gop.found_existing) continue;
711 gop.value_ptr.* = {};726 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);
713 }728 }
714}729}
715730
...@@ -802,8 +817,6 @@ pub fn updateExports(...@@ -802,8 +817,6 @@ pub fn updateExports(
802 },817 },
803 };818 };
804 const ctype_pool = &decl_block.ctype_pool;819 const ctype_pool = &decl_block.ctype_pool;
805 const fwd_decl = &self.fwd_decl_buf;
806 fwd_decl.clearRetainingCapacity();
807 var dg: codegen.DeclGen = .{820 var dg: codegen.DeclGen = .{
808 .gpa = gpa,821 .gpa = gpa,
809 .pt = pt,822 .pt = pt,
...@@ -812,20 +825,24 @@ pub fn updateExports(...@@ -812,20 +825,24 @@ pub fn updateExports(
812 .pass = pass,825 .pass = pass,
813 .is_naked_fn = false,826 .is_naked_fn = false,
814 .expected_block = null,827 .expected_block = null,
815 .fwd_decl = fwd_decl.toManaged(gpa),828 .fwd_decl = undefined,
816 .ctype_pool = decl_block.ctype_pool,829 .ctype_pool = decl_block.ctype_pool,
817 .scratch = .{},830 .scratch = .initBuffer(self.scratch_buf),
818 .uavs = .empty,831 .uavs = .empty,
819 };832 };
833 dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
820 defer {834 defer {
821 assert(dg.uavs.count() == 0);835 assert(dg.uavs.count() == 0);
822 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
823 ctype_pool.* = dg.ctype_pool.move();836 ctype_pool.* = dg.ctype_pool.move();
824 ctype_pool.freeUnusedCapacity(gpa);837 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();
826 }841 }
827 try codegen.genExports(&dg, exported, export_indices);842 codegen.genExports(&dg, exported, export_indices) catch |err| switch (err) {
828 exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };843 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
844 };
845 exported_block.* = .{ .fwd_decl = try self.addString(&.{&dg.fwd_decl}) };
829}846}
830847
831pub fn deleteExport(848pub fn deleteExport(