authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-20 20:50:19-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-21 00:00:19-05:00
log064b355912dd85bd06ee87101066ed0db2783796
tree82917d6c0b3d7628b45d0d823b683d0c355197e0
parentcf7200e8f9c995bae8bedaf3c727fe710a93f1e9

CBE: use CType for type definitions


4 files changed, 1568 insertions(+), 812 deletions(-)

src/Compilation.zig+1-1
......@@ -3273,7 +3273,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
32733273 .gpa = gpa,
32743274 .module = module,
32753275 .error_msg = null,
3276 .decl_index = decl_index,
3276 .decl_index = decl_index.toOptional(),
32773277 .decl = decl,
32783278 .fwd_decl = fwd_decl.toManaged(gpa),
32793279 .ctypes = .{},
src/codegen/c.zig+723-496
......@@ -31,6 +31,7 @@ pub const CType = @import("c/type.zig").CType;
3131
3232pub const CValue = union(enum) {
3333 none: void,
34 new_local: LocalIndex,
3435 local: LocalIndex,
3536 /// Address of a local.
3637 local_ref: LocalIndex,
......@@ -38,6 +39,8 @@ pub const CValue = union(enum) {
3839 constant: Air.Inst.Ref,
3940 /// Index into the parameters
4041 arg: usize,
42 /// The payload field of a parameter
43 arg_array: usize,
4144 /// Index into a tuple's fields
4245 field: usize,
4346 /// By-value
......@@ -298,7 +301,7 @@ pub const Function = struct {
298301 const alignment = 0;
299302 const decl_c_value = try f.allocLocalValue(ty, alignment);
300303 const gpa = f.object.dg.gpa;
301 try f.allocs.put(gpa, decl_c_value.local, true);
304 try f.allocs.put(gpa, decl_c_value.new_local, true);
302305 try writer.writeAll("static ");
303306 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);
304307 try writer.writeAll(" = ");
......@@ -330,12 +333,12 @@ pub const Function = struct {
330333 .alignment = alignment,
331334 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),
332335 });
333 return CValue{ .local = @intCast(LocalIndex, f.locals.items.len - 1) };
336 return CValue{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
334337 }
335338
336339 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
337340 const result = try f.allocAlignedLocal(ty, .mut, 0);
338 log.debug("%{d}: allocating t{d}", .{ inst, result.local });
341 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
339342 return result;
340343 }
341344
......@@ -349,7 +352,7 @@ pub const Function = struct {
349352 if (local.alignment >= alignment) {
350353 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
351354 _ = locals_list.swapRemove(i);
352 return CValue{ .local = local_index };
355 return CValue{ .new_local = local_index };
353356 }
354357 }
355358 }
......@@ -488,8 +491,8 @@ pub const Object = struct {
488491pub const DeclGen = struct {
489492 gpa: std.mem.Allocator,
490493 module: *Module,
491 decl: *Decl,
492 decl_index: Decl.Index,
494 decl: ?*Decl,
495 decl_index: Decl.OptionalIndex,
493496 fwd_decl: std.ArrayList(u8),
494497 error_msg: ?*Module.ErrorMsg,
495498 ctypes: CType.Store,
......@@ -497,7 +500,7 @@ pub const DeclGen = struct {
497500 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
498501 @setCold(true);
499502 const src = LazySrcLoc.nodeOffset(0);
500 const src_loc = src.toSrcLoc(dg.decl);
503 const src_loc = src.toSrcLoc(dg.decl.?);
501504 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
502505 return error.AnalysisFail;
503506 }
......@@ -816,7 +819,7 @@ pub const DeclGen = struct {
816819
817820 empty = false;
818821 }
819 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
822
820823 return writer.writeByte('}');
821824 },
822825 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
......@@ -1287,7 +1290,6 @@ pub const DeclGen = struct {
12871290
12881291 empty = false;
12891292 }
1290 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
12911293 try writer.writeByte('}');
12921294 },
12931295 .Packed => {
......@@ -1304,7 +1306,7 @@ pub const DeclGen = struct {
13041306 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
13051307
13061308 var eff_num_fields: usize = 0;
1307 for (field_vals, 0..) |_, index| {
1309 for (0..field_vals.len) |index| {
13081310 const field_ty = ty.structFieldType(index);
13091311 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
13101312
......@@ -1408,6 +1410,7 @@ pub const DeclGen = struct {
14081410 return;
14091411 }
14101412
1413 var has_payload_init = false;
14111414 try writer.writeByte('{');
14121415 if (ty.unionTagTypeSafety()) |tag_ty| {
14131416 const layout = ty.unionGetLayout(target);
......@@ -1416,7 +1419,10 @@ pub const DeclGen = struct {
14161419 try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);
14171420 try writer.writeAll(", ");
14181421 }
1419 try writer.writeAll(".payload = {");
1422 if (!ty.unionHasAllZeroBitFieldTypes()) {
1423 try writer.writeAll(".payload = {");
1424 has_payload_init = true;
1425 }
14201426 }
14211427
14221428 var it = ty.unionFields().iterator();
......@@ -1428,8 +1434,8 @@ pub const DeclGen = struct {
14281434 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});
14291435 try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);
14301436 break;
1431 } else try writer.writeAll(".empty_union = 0");
1432 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
1437 }
1438 if (has_payload_init) try writer.writeByte('}');
14331439 try writer.writeByte('}');
14341440 },
14351441
......@@ -1452,337 +1458,61 @@ pub const DeclGen = struct {
14521458 }
14531459
14541460 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {
1455 const fn_info = dg.decl.ty.fnInfo();
1461 const store = &dg.ctypes.set;
1462 const module = dg.module;
1463
1464 const fn_ty = dg.decl.?.ty;
1465 const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) {
1466 .Forward => .forward,
1467 .Complete => .complete,
1468 });
1469
1470 const fn_info = fn_ty.fnInfo();
14561471 if (fn_info.cc == .Naked) {
14571472 switch (kind) {
14581473 .Forward => try w.writeAll("zig_naked_decl "),
14591474 .Complete => try w.writeAll("zig_naked "),
14601475 }
14611476 }
1462 if (dg.decl.val.castTag(.function)) |func_payload|
1477 if (dg.decl.?.val.castTag(.function)) |func_payload|
14631478 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
14641479
1465 const target = dg.module.getTarget();
1466 var ret_buf: LowerFnRetTyBuffer = undefined;
1467 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1468
1469 try dg.renderType(w, ret_ty, kind);
1470 try w.writeByte(' ');
1480 const trailing = try renderTypePrefix(
1481 dg.decl_index,
1482 store.*,
1483 module,
1484 w,
1485 fn_cty_idx,
1486 .suffix,
1487 CQualifiers.init(.{}),
1488 );
1489 try w.print("{}", .{trailing});
14711490
14721491 if (toCallingConvention(fn_info.cc)) |call_conv| {
14731492 try w.print("zig_callconv({s}) ", .{call_conv});
14741493 }
14751494
1476 if (fn_info.alignment > 0 and kind == .Complete) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1495 if (fn_info.alignment > 0 and kind == .Complete) {
1496 try w.print(" zig_align_fn({})", .{fn_info.alignment});
1497 }
14771498
1478 try dg.renderDeclName(w, dg.decl_index, export_index);
1479 try w.writeByte('(');
1499 try dg.renderDeclName(w, dg.decl_index.unwrap().?, export_index);
14801500
1481 var index: usize = 0;
1482 for (fn_info.param_types) |param_type| {
1483 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1484 if (index > 0) try w.writeAll(", ");
1485 const name = CValue{ .arg = index };
1486 try dg.renderTypeAndName(w, param_type, name, .@"const", 0, kind);
1487 index += 1;
1488 }
1501 try renderTypeSuffix(dg.decl_index, store.*, module, w, fn_cty_idx, .suffix);
14891502
1490 if (fn_info.is_var_args) {
1491 if (index > 0) try w.writeAll(", ");
1492 try w.writeAll("...");
1493 } else if (index == 0) {
1494 try dg.renderType(w, Type.void, kind);
1503 if (fn_info.alignment > 0 and kind == .Forward) {
1504 try w.print(" zig_align_fn({})", .{fn_info.alignment});
14951505 }
1496 try w.writeByte(')');
1497 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
14981506 }
14991507
15001508 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
15011509 return dg.ctypes.indexToCType(idx);
15021510 }
1503 fn typeToCType(dg: *DeclGen, ty: Type) !CType {
1504 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module);
1505 }
1506 fn typeToIndex(dg: *DeclGen, ty: Type) !CType.Index {
1507 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module);
1508 }
1509
1510 const CTypeFix = enum { prefix, suffix };
1511 const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1512 const CTypeRenderTrailing = enum {
1513 no_space,
1514 maybe_space,
1515
1516 pub fn format(
1517 self: @This(),
1518 comptime fmt: []const u8,
1519 _: std.fmt.FormatOptions,
1520 w: anytype,
1521 ) @TypeOf(w).Error!void {
1522 if (fmt.len != 0)
1523 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1524 @typeName(@This()) ++ "'");
1525 comptime assert(fmt.len == 0);
1526 switch (self) {
1527 .no_space => {},
1528 .maybe_space => try w.writeByte(' '),
1529 }
1530 }
1531 };
1532 fn renderTypePrefix(
1533 dg: *DeclGen,
1534 w: anytype,
1535 idx: CType.Index,
1536 parent_fix: CTypeFix,
1537 qualifiers: CQualifiers,
1538 ) @TypeOf(w).Error!CTypeRenderTrailing {
1539 var trailing = CTypeRenderTrailing.maybe_space;
1540
1541 const cty = dg.indexToCType(idx);
1542 switch (cty.tag()) {
1543 .void,
1544 .char,
1545 .@"signed char",
1546 .short,
1547 .int,
1548 .long,
1549 .@"long long",
1550 ._Bool,
1551 .@"unsigned char",
1552 .@"unsigned short",
1553 .@"unsigned int",
1554 .@"unsigned long",
1555 .@"unsigned long long",
1556 .float,
1557 .double,
1558 .@"long double",
1559 .bool,
1560 .size_t,
1561 .ptrdiff_t,
1562 .uint8_t,
1563 .int8_t,
1564 .uint16_t,
1565 .int16_t,
1566 .uint32_t,
1567 .int32_t,
1568 .uint64_t,
1569 .int64_t,
1570 .uintptr_t,
1571 .intptr_t,
1572 .zig_u128,
1573 .zig_i128,
1574 .zig_f16,
1575 .zig_f32,
1576 .zig_f64,
1577 .zig_f80,
1578 .zig_f128,
1579 => |tag| try w.writeAll(@tagName(tag)),
1580
1581 .pointer,
1582 .pointer_const,
1583 .pointer_volatile,
1584 .pointer_const_volatile,
1585 => |tag| {
1586 const child_idx = cty.cast(CType.Payload.Child).?.data;
1587 try w.print("{}*", .{try dg.renderTypePrefix(w, child_idx, .prefix, CQualifiers.init(.{
1588 .@"const" = switch (tag) {
1589 .pointer, .pointer_volatile => false,
1590 .pointer_const, .pointer_const_volatile => true,
1591 else => unreachable,
1592 },
1593 .@"volatile" = switch (tag) {
1594 .pointer, .pointer_const => false,
1595 .pointer_volatile, .pointer_const_volatile => true,
1596 else => unreachable,
1597 },
1598 }))});
1599 trailing = .no_space;
1600 },
1601
1602 .array,
1603 .vector,
1604 => {
1605 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
1606 const child_trailing = try dg.renderTypePrefix(w, child_idx, .suffix, qualifiers);
1607 switch (parent_fix) {
1608 .prefix => {
1609 try w.print("{}(", .{child_trailing});
1610 return .no_space;
1611 },
1612 .suffix => return child_trailing,
1613 }
1614 },
1615
1616 .fwd_struct,
1617 .fwd_union,
1618 .anon_struct,
1619 .packed_anon_struct,
1620 => |tag| try w.print("{s} {}__{d}", .{
1621 switch (tag) {
1622 .fwd_struct,
1623 .anon_struct,
1624 .packed_anon_struct,
1625 => "struct",
1626 .fwd_union => "union",
1627 else => unreachable,
1628 },
1629 fmtIdent(switch (tag) {
1630 .fwd_struct,
1631 .fwd_union,
1632 => mem.span(dg.module.declPtr(cty.cast(CType.Payload.FwdDecl).?.data).name),
1633 .anon_struct,
1634 .packed_anon_struct,
1635 => "anon",
1636 else => unreachable,
1637 }),
1638 idx,
1639 }),
1640
1641 .@"struct",
1642 .packed_struct,
1643 .@"union",
1644 .packed_union,
1645 => return dg.renderTypePrefix(
1646 w,
1647 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
1648 parent_fix,
1649 qualifiers,
1650 ),
1651
1652 .function,
1653 .varargs_function,
1654 => {
1655 const child_trailing = try dg.renderTypePrefix(
1656 w,
1657 cty.cast(CType.Payload.Function).?.data.return_type,
1658 .suffix,
1659 CQualifiers.initEmpty(),
1660 );
1661 switch (parent_fix) {
1662 .prefix => {
1663 try w.print("{}(", .{child_trailing});
1664 return .no_space;
1665 },
1666 .suffix => return child_trailing,
1667 }
1668 },
1669 }
1670
1671 var qualifier_it = qualifiers.iterator();
1672 while (qualifier_it.next()) |qualifier| {
1673 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
1674 trailing = .maybe_space;
1675 }
1676
1677 return trailing;
1511 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
1512 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
16781513 }
1679 fn renderTypeSuffix(
1680 dg: *DeclGen,
1681 w: anytype,
1682 idx: CType.Index,
1683 parent_fix: CTypeFix,
1684 ) @TypeOf(w).Error!void {
1685 const cty = dg.indexToCType(idx);
1686 switch (cty.tag()) {
1687 .void,
1688 .char,
1689 .@"signed char",
1690 .short,
1691 .int,
1692 .long,
1693 .@"long long",
1694 ._Bool,
1695 .@"unsigned char",
1696 .@"unsigned short",
1697 .@"unsigned int",
1698 .@"unsigned long",
1699 .@"unsigned long long",
1700 .float,
1701 .double,
1702 .@"long double",
1703 .bool,
1704 .size_t,
1705 .ptrdiff_t,
1706 .uint8_t,
1707 .int8_t,
1708 .uint16_t,
1709 .int16_t,
1710 .uint32_t,
1711 .int32_t,
1712 .uint64_t,
1713 .int64_t,
1714 .uintptr_t,
1715 .intptr_t,
1716 .zig_u128,
1717 .zig_i128,
1718 .zig_f16,
1719 .zig_f32,
1720 .zig_f64,
1721 .zig_f80,
1722 .zig_f128,
1723 => {},
1724
1725 .pointer,
1726 .pointer_const,
1727 .pointer_volatile,
1728 .pointer_const_volatile,
1729 => try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Child).?.data, .prefix),
1730
1731 .array,
1732 .vector,
1733 => {
1734 switch (parent_fix) {
1735 .prefix => try w.writeByte(')'),
1736 .suffix => {},
1737 }
1738
1739 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
1740 try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Sequence).?.data.elem_type, .suffix);
1741 },
1742
1743 .fwd_struct,
1744 .fwd_union,
1745 .anon_struct,
1746 .packed_anon_struct,
1747 .@"struct",
1748 .@"union",
1749 .packed_struct,
1750 .packed_union,
1751 => {},
1752
1753 .function,
1754 .varargs_function,
1755 => |tag| {
1756 switch (parent_fix) {
1757 .prefix => try w.writeByte(')'),
1758 .suffix => {},
1759 }
1760
1761 const data = cty.cast(CType.Payload.Function).?.data;
1762
1763 try w.writeByte('(');
1764 var need_comma = false;
1765 for (data.param_types) |param_type| {
1766 if (need_comma) try w.writeAll(", ");
1767 need_comma = true;
1768 _ = try dg.renderTypePrefix(w, param_type, .suffix, CQualifiers.initEmpty());
1769 try dg.renderTypeSuffix(w, param_type, .suffix);
1770 }
1771 switch (tag) {
1772 .function => {},
1773 .varargs_function => {
1774 if (need_comma) try w.writeAll(", ");
1775 need_comma = true;
1776 try w.writeAll("...");
1777 },
1778 else => unreachable,
1779 }
1780 if (!need_comma) try w.writeAll("void");
1781 try w.writeByte(')');
1782
1783 try dg.renderTypeSuffix(w, data.return_type, .suffix);
1784 },
1785 }
1514 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1515 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
17861516 }
17871517
17881518 /// Renders a type as a single identifier, generating intermediate typedefs
......@@ -1803,9 +1533,19 @@ pub const DeclGen = struct {
18031533 t: Type,
18041534 _: TypedefKind,
18051535 ) error{ OutOfMemory, AnalysisFail }!void {
1806 const idx = try dg.typeToIndex(t);
1807 _ = try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.initEmpty());
1808 try dg.renderTypeSuffix(w, idx, .suffix);
1536 const store = &dg.ctypes.set;
1537 const module = dg.module;
1538 const idx = try dg.typeToIndex(t, .complete);
1539 _ = try renderTypePrefix(
1540 dg.decl_index,
1541 store.*,
1542 module,
1543 w,
1544 idx,
1545 .suffix,
1546 CQualifiers.init(.{}),
1547 );
1548 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
18091549 }
18101550
18111551 const IntCastContext = union(enum) {
......@@ -1939,24 +1679,28 @@ pub const DeclGen = struct {
19391679 alignment: u32,
19401680 _: TypedefKind,
19411681 ) error{ OutOfMemory, AnalysisFail }!void {
1942 if (alignment != 0) {
1943 const abi_alignment = ty.abiAlignment(dg.module.getTarget());
1944 if (alignment < abi_alignment) {
1945 try w.print("zig_under_align({}) ", .{alignment});
1946 } else if (alignment > abi_alignment) {
1947 try w.print("zig_align({}) ", .{alignment});
1948 }
1949 }
1682 const store = &dg.ctypes.set;
1683 const module = dg.module;
19501684
1951 const idx = try dg.typeToIndex(ty);
1952 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{
1953 .@"const" = switch (mutability) {
1954 .mut => false,
1955 .@"const" => true,
1956 },
1957 }))});
1685 if (alignment != 0) switch (std.math.order(alignment, ty.abiAlignment(dg.module.getTarget()))) {
1686 .lt => try w.print("zig_under_align({}) ", .{alignment}),
1687 .eq => {},
1688 .gt => try w.print("zig_align({}) ", .{alignment}),
1689 };
1690
1691 const idx = try dg.typeToIndex(ty, .complete);
1692 const trailing = try renderTypePrefix(
1693 dg.decl_index,
1694 store.*,
1695 module,
1696 w,
1697 idx,
1698 .suffix,
1699 CQualifiers.init(.{ .@"const" = mutability == .@"const" }),
1700 );
1701 try w.print("{}", .{trailing});
19581702 try dg.writeCValue(w, name);
1959 try dg.renderTypeSuffix(w, idx, .suffix);
1703 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
19601704 }
19611705
19621706 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
......@@ -2029,10 +1773,11 @@ pub const DeclGen = struct {
20291773 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20301774 switch (c_value) {
20311775 .none => unreachable,
2032 .local => |i| return w.print("t{d}", .{i}),
1776 .local, .new_local => |i| return w.print("t{d}", .{i}),
20331777 .local_ref => |i| return w.print("&t{d}", .{i}),
20341778 .constant => unreachable,
20351779 .arg => |i| return w.print("a{d}", .{i}),
1780 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
20361781 .field => |i| return w.print("f{d}", .{i}),
20371782 .decl => |decl| return dg.renderDeclName(w, decl, 0),
20381783 .decl_ref => |decl| {
......@@ -2048,10 +1793,15 @@ pub const DeclGen = struct {
20481793 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20491794 switch (c_value) {
20501795 .none => unreachable,
2051 .local => |i| return w.print("(*t{d})", .{i}),
1796 .local, .new_local => |i| return w.print("(*t{d})", .{i}),
20521797 .local_ref => |i| return w.print("t{d}", .{i}),
20531798 .constant => unreachable,
20541799 .arg => |i| return w.print("(*a{d})", .{i}),
1800 .arg_array => |i| {
1801 try w.writeAll("(*");
1802 try dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" });
1803 return w.writeByte(')');
1804 },
20551805 .field => |i| return w.print("f{d}", .{i}),
20561806 .decl => |decl| {
20571807 try w.writeAll("(*");
......@@ -2078,7 +1828,7 @@ pub const DeclGen = struct {
20781828 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
20791829 switch (c_value) {
20801830 .none, .constant, .field, .undef => unreachable,
2081 .local, .arg, .decl, .identifier, .bytes => {
1831 .new_local, .local, .arg, .arg_array, .decl, .identifier, .bytes => {
20821832 try dg.writeCValue(writer, c_value);
20831833 try writer.writeAll("->");
20841834 },
......@@ -2205,10 +1955,491 @@ pub const DeclGen = struct {
22051955 }
22061956};
22071957
2208pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {
1958const CTypeFix = enum { prefix, suffix };
1959const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1960const CTypeRenderTrailing = enum {
1961 no_space,
1962 maybe_space,
1963
1964 pub fn format(
1965 self: @This(),
1966 comptime fmt: []const u8,
1967 _: std.fmt.FormatOptions,
1968 w: anytype,
1969 ) @TypeOf(w).Error!void {
1970 if (fmt.len != 0)
1971 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1972 @typeName(@This()) ++ "'");
1973 comptime assert(fmt.len == 0);
1974 switch (self) {
1975 .no_space => {},
1976 .maybe_space => try w.writeByte(' '),
1977 }
1978 }
1979};
1980fn renderTypeName(
1981 mod: *Module,
1982 w: anytype,
1983 idx: CType.Index,
1984 cty: CType,
1985 attributes: []const u8,
1986) !void {
1987 switch (cty.tag()) {
1988 else => unreachable,
1989
1990 .fwd_anon_struct,
1991 .fwd_anon_union,
1992 => |tag| try w.print("{s} {s}anon__lazy_{d}", .{
1993 @tagName(tag)["fwd_anon_".len..],
1994 attributes,
1995 idx,
1996 }),
1997
1998 .fwd_struct,
1999 .fwd_union,
2000 => |tag| {
2001 const owner_decl = cty.cast(CType.Payload.FwdDecl).?.data;
2002 try w.print("{s} {s}{}__{d}", .{
2003 @tagName(tag)["fwd_".len..],
2004 attributes,
2005 fmtIdent(mem.span(mod.declPtr(owner_decl).name)),
2006 @enumToInt(owner_decl),
2007 });
2008 },
2009 }
2010}
2011fn renderTypePrefix(
2012 decl: Decl.OptionalIndex,
2013 store: CType.Store.Set,
2014 mod: *Module,
2015 w: anytype,
2016 idx: CType.Index,
2017 parent_fix: CTypeFix,
2018 qualifiers: CQualifiers,
2019) @TypeOf(w).Error!CTypeRenderTrailing {
2020 var trailing = CTypeRenderTrailing.maybe_space;
2021
2022 const cty = store.indexToCType(idx);
2023 switch (cty.tag()) {
2024 .void,
2025 .char,
2026 .@"signed char",
2027 .short,
2028 .int,
2029 .long,
2030 .@"long long",
2031 ._Bool,
2032 .@"unsigned char",
2033 .@"unsigned short",
2034 .@"unsigned int",
2035 .@"unsigned long",
2036 .@"unsigned long long",
2037 .float,
2038 .double,
2039 .@"long double",
2040 .bool,
2041 .size_t,
2042 .ptrdiff_t,
2043 .uint8_t,
2044 .int8_t,
2045 .uint16_t,
2046 .int16_t,
2047 .uint32_t,
2048 .int32_t,
2049 .uint64_t,
2050 .int64_t,
2051 .uintptr_t,
2052 .intptr_t,
2053 .zig_u128,
2054 .zig_i128,
2055 .zig_f16,
2056 .zig_f32,
2057 .zig_f64,
2058 .zig_f80,
2059 .zig_f128,
2060 => |tag| try w.writeAll(@tagName(tag)),
2061
2062 .pointer,
2063 .pointer_const,
2064 .pointer_volatile,
2065 .pointer_const_volatile,
2066 => |tag| {
2067 const child_idx = cty.cast(CType.Payload.Child).?.data;
2068 const child_trailing = try renderTypePrefix(
2069 decl,
2070 store,
2071 mod,
2072 w,
2073 child_idx,
2074 .prefix,
2075 CQualifiers.init(.{ .@"const" = switch (tag) {
2076 .pointer, .pointer_volatile => false,
2077 .pointer_const, .pointer_const_volatile => true,
2078 else => unreachable,
2079 }, .@"volatile" = switch (tag) {
2080 .pointer, .pointer_const => false,
2081 .pointer_volatile, .pointer_const_volatile => true,
2082 else => unreachable,
2083 } }),
2084 );
2085 try w.print("{}*", .{child_trailing});
2086 trailing = .no_space;
2087 },
2088
2089 .array,
2090 .vector,
2091 => {
2092 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
2093 const child_trailing = try renderTypePrefix(
2094 decl,
2095 store,
2096 mod,
2097 w,
2098 child_idx,
2099 .suffix,
2100 qualifiers,
2101 );
2102 switch (parent_fix) {
2103 .prefix => {
2104 try w.print("{}(", .{child_trailing});
2105 return .no_space;
2106 },
2107 .suffix => return child_trailing,
2108 }
2109 },
2110
2111 .fwd_anon_struct,
2112 .fwd_anon_union,
2113 => if (decl.unwrap()) |decl_index|
2114 try w.print("anon__{d}_{d}", .{ @enumToInt(decl_index), idx })
2115 else
2116 try renderTypeName(mod, w, idx, cty, ""),
2117
2118 .fwd_struct,
2119 .fwd_union,
2120 => try renderTypeName(mod, w, idx, cty, ""),
2121
2122 .unnamed_struct,
2123 .unnamed_union,
2124 .packed_unnamed_struct,
2125 .packed_unnamed_union,
2126 => |tag| {
2127 try w.print("{s} {s}", .{
2128 @tagName(tag)["unnamed_".len..],
2129 if (cty.isPacked()) "zig_packed(" else "",
2130 });
2131 try renderAggregateFields(mod, w, store, cty, 1);
2132 if (cty.isPacked()) try w.writeByte(')');
2133 },
2134
2135 .anon_struct,
2136 .anon_union,
2137 .@"struct",
2138 .@"union",
2139 .packed_struct,
2140 .packed_union,
2141 => return renderTypePrefix(
2142 decl,
2143 store,
2144 mod,
2145 w,
2146 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
2147 parent_fix,
2148 qualifiers,
2149 ),
2150
2151 .function,
2152 .varargs_function,
2153 => {
2154 const child_trailing = try renderTypePrefix(
2155 decl,
2156 store,
2157 mod,
2158 w,
2159 cty.cast(CType.Payload.Function).?.data.return_type,
2160 .suffix,
2161 CQualifiers.init(.{}),
2162 );
2163 switch (parent_fix) {
2164 .prefix => {
2165 try w.print("{}(", .{child_trailing});
2166 return .no_space;
2167 },
2168 .suffix => return child_trailing,
2169 }
2170 },
2171 }
2172
2173 var qualifier_it = qualifiers.iterator();
2174 while (qualifier_it.next()) |qualifier| {
2175 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2176 trailing = .maybe_space;
2177 }
2178
2179 return trailing;
2180}
2181fn renderTypeSuffix(
2182 decl: Decl.OptionalIndex,
2183 store: CType.Store.Set,
2184 mod: *Module,
2185 w: anytype,
2186 idx: CType.Index,
2187 parent_fix: CTypeFix,
2188) @TypeOf(w).Error!void {
2189 const cty = store.indexToCType(idx);
2190 switch (cty.tag()) {
2191 .void,
2192 .char,
2193 .@"signed char",
2194 .short,
2195 .int,
2196 .long,
2197 .@"long long",
2198 ._Bool,
2199 .@"unsigned char",
2200 .@"unsigned short",
2201 .@"unsigned int",
2202 .@"unsigned long",
2203 .@"unsigned long long",
2204 .float,
2205 .double,
2206 .@"long double",
2207 .bool,
2208 .size_t,
2209 .ptrdiff_t,
2210 .uint8_t,
2211 .int8_t,
2212 .uint16_t,
2213 .int16_t,
2214 .uint32_t,
2215 .int32_t,
2216 .uint64_t,
2217 .int64_t,
2218 .uintptr_t,
2219 .intptr_t,
2220 .zig_u128,
2221 .zig_i128,
2222 .zig_f16,
2223 .zig_f32,
2224 .zig_f64,
2225 .zig_f80,
2226 .zig_f128,
2227 => {},
2228
2229 .pointer,
2230 .pointer_const,
2231 .pointer_volatile,
2232 .pointer_const_volatile,
2233 => try renderTypeSuffix(decl, store, mod, w, cty.cast(CType.Payload.Child).?.data, .prefix),
2234
2235 .array,
2236 .vector,
2237 => {
2238 switch (parent_fix) {
2239 .prefix => try w.writeByte(')'),
2240 .suffix => {},
2241 }
2242
2243 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
2244 try renderTypeSuffix(
2245 decl,
2246 store,
2247 mod,
2248 w,
2249 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2250 .suffix,
2251 );
2252 },
2253
2254 .fwd_anon_struct,
2255 .fwd_anon_union,
2256 .fwd_struct,
2257 .fwd_union,
2258 .unnamed_struct,
2259 .unnamed_union,
2260 .packed_unnamed_struct,
2261 .packed_unnamed_union,
2262 .anon_struct,
2263 .anon_union,
2264 .@"struct",
2265 .@"union",
2266 .packed_struct,
2267 .packed_union,
2268 => {},
2269
2270 .function,
2271 .varargs_function,
2272 => |tag| {
2273 switch (parent_fix) {
2274 .prefix => try w.writeByte(')'),
2275 .suffix => {},
2276 }
2277
2278 const data = cty.cast(CType.Payload.Function).?.data;
2279
2280 try w.writeByte('(');
2281 var need_comma = false;
2282 for (data.param_types, 0..) |param_type, param_i| {
2283 if (need_comma) try w.writeAll(", ");
2284 need_comma = true;
2285 const trailing = try renderTypePrefix(
2286 decl,
2287 store,
2288 mod,
2289 w,
2290 param_type,
2291 .suffix,
2292 CQualifiers.init(.{}),
2293 );
2294 try w.print("{}a{d}", .{ trailing, param_i });
2295 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix);
2296 }
2297 switch (tag) {
2298 .function => {},
2299 .varargs_function => {
2300 if (need_comma) try w.writeAll(", ");
2301 need_comma = true;
2302 try w.writeAll("...");
2303 },
2304 else => unreachable,
2305 }
2306 if (!need_comma) try w.writeAll("void");
2307 try w.writeByte(')');
2308
2309 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix);
2310 },
2311 }
2312}
2313fn renderAggregateFields(
2314 mod: *Module,
2315 writer: anytype,
2316 store: CType.Store.Set,
2317 cty: CType,
2318 indent: usize,
2319) !void {
2320 try writer.writeAll("{\n");
2321 const fields = cty.fields();
2322 for (fields) |field| {
2323 try writer.writeByteNTimes(' ', indent + 1);
2324 switch (std.math.order(field.alignas.@"align", field.alignas.abi)) {
2325 .lt => try writer.print("zig_under_align({}) ", .{field.alignas.getAlign()}),
2326 .eq => {},
2327 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
2328 }
2329 const trailing = try renderTypePrefix(
2330 .none,
2331 store,
2332 mod,
2333 writer,
2334 field.type,
2335 .suffix,
2336 CQualifiers.init(.{}),
2337 );
2338 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2339 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix);
2340 try writer.writeAll(";\n");
2341 }
2342 try writer.writeByteNTimes(' ', indent);
2343 try writer.writeByte('}');
2344}
2345
2346pub fn genTypeDecl(
2347 mod: *Module,
2348 writer: anytype,
2349 global_store: CType.Store.Set,
2350 global_idx: CType.Index,
2351 decl: Decl.OptionalIndex,
2352 decl_store: CType.Store.Set,
2353 decl_idx: CType.Index,
2354 found_existing: bool,
2355) !void {
2356 const global_cty = global_store.indexToCType(global_idx);
2357 switch (global_cty.tag()) {
2358 .fwd_anon_struct => if (decl != .none) {
2359 try writer.writeAll("typedef ");
2360 _ = try renderTypePrefix(
2361 .none,
2362 global_store,
2363 mod,
2364 writer,
2365 global_idx,
2366 .suffix,
2367 CQualifiers.init(.{}),
2368 );
2369 try writer.writeByte(' ');
2370 _ = try renderTypePrefix(
2371 decl,
2372 decl_store,
2373 mod,
2374 writer,
2375 decl_idx,
2376 .suffix,
2377 CQualifiers.init(.{}),
2378 );
2379 try writer.writeAll(";\n");
2380 },
2381
2382 .fwd_struct,
2383 .fwd_union,
2384 .anon_struct,
2385 .anon_union,
2386 .@"struct",
2387 .@"union",
2388 .packed_struct,
2389 .packed_union,
2390 => |tag| if (!found_existing) {
2391 switch (tag) {
2392 .fwd_struct,
2393 .fwd_union,
2394 => {
2395 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2396 _ = try renderTypePrefix(
2397 .none,
2398 global_store,
2399 mod,
2400 writer,
2401 global_idx,
2402 .suffix,
2403 CQualifiers.init(.{}),
2404 );
2405 try writer.writeAll("; // ");
2406 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
2407 try writer.writeByte('\n');
2408 },
2409
2410 .anon_struct,
2411 .anon_union,
2412 .@"struct",
2413 .@"union",
2414 .packed_struct,
2415 .packed_union,
2416 => {
2417 const fwd_idx = global_cty.cast(CType.Payload.Aggregate).?.data.fwd_decl;
2418 try renderTypeName(
2419 mod,
2420 writer,
2421 fwd_idx,
2422 global_store.indexToCType(fwd_idx),
2423 if (global_cty.isPacked()) "zig_packed(" else "",
2424 );
2425 try writer.writeByte(' ');
2426 try renderAggregateFields(mod, writer, global_store, global_cty, 0);
2427 if (global_cty.isPacked()) try writer.writeByte(')');
2428 try writer.writeAll(";\n");
2429 },
2430
2431 else => unreachable,
2432 }
2433 },
2434
2435 else => {},
2436 }
2437}
2438
2439pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
22092440 var it = mod.global_assembly.valueIterator();
22102441 while (it.next()) |asm_source| {
2211 try code.writer().print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
2442 try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
22122443 }
22132444}
22142445
......@@ -2279,14 +2510,16 @@ fn genExports(o: *Object) !void {
22792510 defer tracy.end();
22802511
22812512 const fwd_decl_writer = o.dg.fwd_decl.writer();
2282 if (o.dg.module.decl_exports.get(o.dg.decl_index)) |exports| for (exports.items[1..], 0..) |@"export", i| {
2283 try fwd_decl_writer.writeAll("zig_export(");
2284 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, 1 + i));
2285 try fwd_decl_writer.print(", {s}, {s});\n", .{
2286 fmtStringLiteral(exports.items[0].options.name),
2287 fmtStringLiteral(@"export".options.name),
2288 });
2289 };
2513 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
2514 for (exports.items[1..], 1..) |@"export", i| {
2515 try fwd_decl_writer.writeAll("zig_export(");
2516 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, i));
2517 try fwd_decl_writer.print(", {s}, {s});\n", .{
2518 fmtStringLiteral(exports.items[0].options.name),
2519 fmtStringLiteral(@"export".options.name),
2520 });
2521 }
2522 }
22902523}
22912524
22922525pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
......@@ -2307,8 +2540,8 @@ pub fn genFunc(f: *Function) !void {
23072540 const o = &f.object;
23082541 const gpa = o.dg.gpa;
23092542 const tv: TypedValue = .{
2310 .ty = o.dg.decl.ty,
2311 .val = o.dg.decl.val,
2543 .ty = o.dg.decl.?.ty,
2544 .val = o.dg.decl.?.val,
23122545 };
23132546
23142547 o.code_header = std.ArrayList(u8).init(gpa);
......@@ -2347,9 +2580,8 @@ pub fn genFunc(f: *Function) !void {
23472580 // missing. These are added now to complete the map. Then we can sort by
23482581 // alignment, descending.
23492582 const free_locals = f.getFreeLocals();
2350 const values = f.allocs.values();
2351 for (f.allocs.keys(), 0..) |local_index, i| {
2352 if (values[i]) continue; // static
2583 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
2584 if (value) continue; // static
23532585 const local = f.locals.items[local_index];
23542586 log.debug("inserting local {d} into free_locals", .{local_index});
23552587 const gop = try free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx());
......@@ -2398,10 +2630,10 @@ pub fn genDecl(o: *Object) !void {
23982630 const tracy = trace(@src());
23992631 defer tracy.end();
24002632
2401 const tv: TypedValue = .{
2402 .ty = o.dg.decl.ty,
2403 .val = o.dg.decl.val,
2404 };
2633 const decl = o.dg.decl.?;
2634 const decl_c_value: CValue = .{ .decl = o.dg.decl_index.unwrap().? };
2635 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };
2636
24052637 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;
24062638 if (tv.val.tag() == .extern_fn) {
24072639 const fwd_decl_writer = o.dg.fwd_decl.writer();
......@@ -2415,11 +2647,9 @@ pub fn genDecl(o: *Object) !void {
24152647 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
24162648 const fwd_decl_writer = o.dg.fwd_decl.writer();
24172649
2418 const decl_c_value = CValue{ .decl = o.dg.decl_index };
2419
24202650 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
24212651 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2422 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
2652 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .mut, decl.@"align", .Complete);
24232653 try fwd_decl_writer.writeAll(";\n");
24242654 try genExports(o);
24252655
......@@ -2428,27 +2658,26 @@ pub fn genDecl(o: *Object) !void {
24282658 const w = o.writer();
24292659 if (!is_global) try w.writeAll("static ");
24302660 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2431 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2432 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
2433 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");
2661 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2662 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .mut, decl.@"align", .Complete);
2663 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
24342664 try w.writeAll(" = ");
24352665 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
24362666 try w.writeByte(';');
24372667 try o.indent_writer.insertNewline();
24382668 } else {
2439 const is_global = o.dg.module.decl_exports.contains(o.dg.decl_index);
2669 const is_global = o.dg.module.decl_exports.contains(decl_c_value.decl);
24402670 const fwd_decl_writer = o.dg.fwd_decl.writer();
2441 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
24422671
24432672 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2444 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
2673 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
24452674 try fwd_decl_writer.writeAll(";\n");
24462675
24472676 const w = o.writer();
24482677 if (!is_global) try w.writeAll("static ");
2449 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2450 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
2451 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");
2678 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2679 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
2680 if (decl.@"linksection" != null) try w.writeAll(", read)");
24522681 try w.writeAll(" = ");
24532682 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
24542683 try w.writeAll(";\n");
......@@ -2460,8 +2689,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
24602689 defer tracy.end();
24612690
24622691 const tv: TypedValue = .{
2463 .ty = dg.decl.ty,
2464 .val = dg.decl.val,
2692 .ty = dg.decl.?.ty,
2693 .val = dg.decl.?.val,
24652694 };
24662695 const writer = dg.fwd_decl.writer();
24672696
......@@ -2499,7 +2728,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
24992728 // zig fmt: off
25002729 .constant => unreachable, // excluded from function bodies
25012730 .const_ty => unreachable, // excluded from function bodies
2502 .arg => airArg(f),
2731 .arg => try airArg(f, inst),
25032732
25042733 .breakpoint => try airBreakpoint(f.object.writer()),
25052734 .ret_addr => try airRetAddr(f, inst),
......@@ -2748,13 +2977,14 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
27482977 .c_va_start => return f.fail("TODO implement c_va_start", .{}),
27492978 // zig fmt: on
27502979 };
2751 if (result_value == .local) {
2752 log.debug("map %{d} to t{d}", .{ inst, result_value.local });
2753 }
2754 switch (result_value) {
2755 .none => {},
2756 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),
2980 if (result_value == .new_local) {
2981 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });
27572982 }
2983 try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) {
2984 .none => continue,
2985 .new_local => |i| .{ .local = i },
2986 else => result_value,
2987 });
27582988 }
27592989}
27602990
......@@ -2979,10 +3209,10 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
29793209 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
29803210 const target = f.object.dg.module.getTarget();
29813211 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
2982 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
3212 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
29833213 const gpa = f.object.dg.module.gpa;
2984 try f.allocs.put(gpa, local.local, false);
2985 return CValue{ .local_ref = local.local };
3214 try f.allocs.put(gpa, local.new_local, false);
3215 return CValue{ .local_ref = local.new_local };
29863216}
29873217
29883218fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -2996,16 +3226,22 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
29963226 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
29973227 const target = f.object.dg.module.getTarget();
29983228 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
2999 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
3229 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
30003230 const gpa = f.object.dg.module.gpa;
3001 try f.allocs.put(gpa, local.local, false);
3002 return CValue{ .local_ref = local.local };
3231 try f.allocs.put(gpa, local.new_local, false);
3232 return CValue{ .local_ref = local.new_local };
30033233}
30043234
3005fn airArg(f: *Function) CValue {
3235fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
3236 const inst_ty = f.air.typeOfIndex(inst);
3237 const inst_cty = try f.object.dg.typeToIndex(inst_ty, .parameter);
3238
30063239 const i = f.next_arg_index;
30073240 f.next_arg_index += 1;
3008 return .{ .arg = i };
3241 return if (inst_cty != try f.object.dg.typeToIndex(inst_ty, .complete))
3242 .{ .arg_array = i }
3243 else
3244 .{ .arg = i };
30093245}
30103246
30113247fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3115,7 +3351,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
31153351 const ret_val = if (is_array) ret_val: {
31163352 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
31173353 try writer.writeAll("memcpy(");
3118 try f.writeCValueMember(writer, array_local, .{ .field = 0 });
3354 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
31193355 try writer.writeAll(", ");
31203356 if (deref)
31213357 try f.writeCValueDeref(writer, operand)
......@@ -3135,14 +3371,13 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
31353371 try f.writeCValue(writer, ret_val, .Other);
31363372 try writer.writeAll(";\n");
31373373 if (is_array) {
3138 try freeLocal(f, inst, ret_val.local, 0);
3374 try freeLocal(f, inst, ret_val.new_local, 0);
31393375 }
31403376 } else {
31413377 try reap(f, inst, &.{un_op});
3142 if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
3378 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked)
31433379 // Not even allowed to return void in a naked function.
31443380 try writer.writeAll("return;\n");
3145 }
31463381 }
31473382 return CValue.none;
31483383}
......@@ -3344,7 +3579,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
33443579 try f.renderTypecast(writer, src_ty);
33453580 try writer.writeAll("))");
33463581 if (src_val == .constant) {
3347 try freeLocal(f, inst, array_src.local, 0);
3582 try freeLocal(f, inst, array_src.new_local, 0);
33483583 }
33493584 } else if (ptr_info.host_size != 0) {
33503585 const host_bits = ptr_info.host_size * 8;
......@@ -3770,8 +4005,12 @@ fn airCall(
37704005 modifier: std.builtin.CallModifier,
37714006) !CValue {
37724007 // Not even allowed to call panic in a naked function.
3773 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
4008 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
4009
37744010 const gpa = f.object.dg.gpa;
4011 const module = f.object.dg.module;
4012 const target = module.getTarget();
4013 const writer = f.object.writer();
37754014
37764015 switch (modifier) {
37774016 .auto => {},
......@@ -3786,8 +4025,28 @@ fn airCall(
37864025
37874026 const resolved_args = try gpa.alloc(CValue, args.len);
37884027 defer gpa.free(resolved_args);
3789 for (args, 0..) |arg, i| {
3790 resolved_args[i] = try f.resolveInst(arg);
4028 for (resolved_args, args) |*resolved_arg, arg| {
4029 const arg_ty = f.air.typeOf(arg);
4030 const arg_cty = try f.object.dg.typeToIndex(arg_ty, .parameter);
4031 if (f.object.dg.indexToCType(arg_cty).tag() == .void) {
4032 resolved_arg.* = .none;
4033 continue;
4034 }
4035 resolved_arg.* = try f.resolveInst(arg);
4036 if (arg_cty != try f.object.dg.typeToIndex(arg_ty, .complete)) {
4037 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
4038 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
4039
4040 const array_local = try f.allocLocal(inst, try lowered_arg_ty.copy(f.arena.allocator()));
4041 try writer.writeAll("memcpy(");
4042 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4043 try writer.writeAll(", ");
4044 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4045 try writer.writeAll(", sizeof(");
4046 try f.renderTypecast(writer, lowered_arg_ty);
4047 try writer.writeAll("));\n");
4048 resolved_arg.* = array_local;
4049 }
37914050 }
37924051
37934052 const callee = try f.resolveInst(pl_op.operand);
......@@ -3804,9 +4063,7 @@ fn airCall(
38044063 .Pointer => callee_ty.childType(),
38054064 else => unreachable,
38064065 };
3807 const writer = f.object.writer();
38084066
3809 const target = f.object.dg.module.getTarget();
38104067 const ret_ty = fn_ty.fnReturnType();
38114068 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
38124069 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
......@@ -3841,7 +4098,7 @@ fn airCall(
38414098 else => break :known,
38424099 };
38434100 };
3844 name = f.object.dg.module.declPtr(fn_decl).name;
4101 name = module.declPtr(fn_decl).name;
38454102 try f.object.dg.renderDeclName(writer, fn_decl, 0);
38464103 break :callee;
38474104 }
......@@ -3851,22 +4108,11 @@ fn airCall(
38514108
38524109 try writer.writeByte('(');
38534110 var args_written: usize = 0;
3854 for (args, 0..) |arg, arg_i| {
3855 const ty = f.air.typeOf(arg);
3856 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;
3857 if (args_written != 0) {
3858 try writer.writeAll(", ");
3859 }
3860 if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and
3861 ty.isCPtr() and ty.childType().tag() == .u8)
3862 {
3863 // Corresponds with hack in renderType .Pointer case.
3864 try writer.writeAll("(char");
3865 if (ty.isConstPtr()) try writer.writeAll(" const");
3866 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
3867 try writer.writeAll(" *)");
3868 }
3869 try f.writeCValue(writer, resolved_args[arg_i], .FunctionArgument);
4111 for (resolved_args) |resolved_arg| {
4112 if (resolved_arg == .none) continue;
4113 if (args_written != 0) try writer.writeAll(", ");
4114 try f.writeCValue(writer, resolved_arg, .FunctionArgument);
4115 if (resolved_arg == .new_local) try freeLocal(f, inst, resolved_arg.new_local, 0);
38704116 args_written += 1;
38714117 }
38724118 try writer.writeAll(");\n");
......@@ -3879,11 +4125,11 @@ fn airCall(
38794125 try writer.writeAll("memcpy(");
38804126 try f.writeCValue(writer, array_local, .FunctionArgument);
38814127 try writer.writeAll(", ");
3882 try f.writeCValueMember(writer, result_local, .{ .field = 0 });
4128 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
38834129 try writer.writeAll(", sizeof(");
38844130 try f.renderTypecast(writer, ret_ty);
38854131 try writer.writeAll("));\n");
3886 try freeLocal(f, inst, result_local.local, 0);
4132 try freeLocal(f, inst, result_local.new_local, 0);
38874133 break :r array_local;
38884134 };
38894135
......@@ -4147,7 +4393,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
41474393 }
41484394
41494395 if (operand == .constant) {
4150 try freeLocal(f, inst, operand_lval.local, 0);
4396 try freeLocal(f, inst, operand_lval.new_local, 0);
41514397 }
41524398
41534399 return local;
......@@ -4193,7 +4439,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
41934439
41944440fn airUnreach(f: *Function) !CValue {
41954441 // Not even allowed to call unreachable in a naked function.
4196 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
4442 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
41974443
41984444 try f.object.writer().writeAll("zig_unreachable();\n");
41994445 return CValue.none;
......@@ -4667,7 +4913,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
46674913 const is_reg = constraint[1] == '{';
46684914 if (is_reg) {
46694915 try f.writeCValueDeref(writer, if (output == .none)
4670 CValue{ .local_ref = local.local }
4916 CValue{ .local_ref = local.new_local }
46714917 else
46724918 try f.resolveInst(output));
46734919 try writer.writeAll(" = ");
......@@ -4967,18 +5213,20 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
49675213 else => .none,
49685214 };
49695215
4970 const FieldLoc = union(enum) {
5216 const field_loc: union(enum) {
49715217 begin: void,
49725218 field: CValue,
49735219 end: void,
4974 };
4975 const field_loc = switch (struct_ty.tag()) {
4976 .@"struct" => switch (struct_ty.containerLayout()) {
4977 .Auto, .Extern => for (struct_ty.structFields().values()[index..], 0..) |field, offset| {
4978 if (field.ty.hasRuntimeBitsIgnoreComptime()) break FieldLoc{ .field = .{
4979 .identifier = struct_ty.structFieldName(index + offset),
4980 } };
4981 } else @as(FieldLoc, .end),
5220 } = switch (struct_ty.tag()) {
5221 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5222 .Auto, .Extern => for (index..struct_ty.structFieldCount()) |field_i| {
5223 if (!struct_ty.structFieldIsComptime(field_i) and
5224 struct_ty.structFieldType(field_i).hasRuntimeBitsIgnoreComptime())
5225 break .{ .field = if (struct_ty.isSimpleTuple())
5226 .{ .field = field_i }
5227 else
5228 .{ .identifier = struct_ty.structFieldName(field_i) } };
5229 } else .end,
49825230 .Packed => if (field_ptr_info.data.host_size == 0) {
49835231 const target = f.object.dg.module.getTarget();
49845232
......@@ -5003,27 +5251,15 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
50035251 try f.writeCValue(writer, struct_ptr, .Other);
50045252 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
50055253 return local;
5006 } else @as(FieldLoc, .begin),
5254 } else .begin,
50075255 },
50085256 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
50095257 try f.writeCValue(writer, struct_ptr, .Other);
50105258 try writer.writeAll(";\n");
50115259 return local;
5012 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) FieldLoc{ .field = .{
5260 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) .{ .field = .{
50135261 .identifier = struct_ty.unionFields().keys()[index],
5014 } } else @as(FieldLoc, .end),
5015 .tuple, .anon_struct => field_name: {
5016 const tuple = struct_ty.tupleFields();
5017 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
5018
5019 var id: usize = 0;
5020 break :field_name for (tuple.values, 0..) |value, i| {
5021 if (value.tag() != .unreachable_value) continue;
5022 if (!tuple.types[i].hasRuntimeBitsIgnoreComptime()) continue;
5023 if (i >= index) break FieldLoc{ .field = .{ .field = id } };
5024 id += 1;
5025 } else @as(FieldLoc, .end);
5026 },
5262 } } else .end,
50275263 else => unreachable,
50285264 };
50295265
......@@ -5076,8 +5312,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
50765312 };
50775313
50785314 const field_name: CValue = switch (struct_ty.tag()) {
5079 .@"struct" => switch (struct_ty.containerLayout()) {
5080 .Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) },
5315 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5316 .Auto, .Extern => if (struct_ty.isSimpleTuple())
5317 .{ .field = extra.field_index }
5318 else
5319 .{ .identifier = struct_ty.structFieldName(extra.field_index) },
50815320 .Packed => {
50825321 const struct_obj = struct_ty.castTag(.@"struct").?.data;
50835322 const int_info = struct_ty.intInfo(target);
......@@ -5135,13 +5374,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
51355374
51365375 const local = try f.allocLocal(inst, inst_ty);
51375376 try writer.writeAll("memcpy(");
5138 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);
5377 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
51395378 try writer.writeAll(", ");
5140 try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument);
5379 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
51415380 try writer.writeAll(", sizeof(");
51425381 try f.renderTypecast(writer, inst_ty);
51435382 try writer.writeAll("));\n");
5144 try freeLocal(f, inst, temp_local.local, 0);
5383 try freeLocal(f, inst, temp_local.new_local, 0);
51455384 return local;
51465385 },
51475386 },
......@@ -5165,22 +5404,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
51655404 try writer.writeAll("));\n");
51665405
51675406 if (struct_byval == .constant) {
5168 try freeLocal(f, inst, operand_lval.local, 0);
5407 try freeLocal(f, inst, operand_lval.new_local, 0);
51695408 }
51705409
51715410 return local;
51725411 } else .{
51735412 .identifier = struct_ty.unionFields().keys()[extra.field_index],
51745413 },
5175 .tuple, .anon_struct => blk: {
5176 const tuple = struct_ty.tupleFields();
5177 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
5178
5179 var id: usize = 0;
5180 for (tuple.values[0..extra.field_index]) |value|
5181 id += @boolToInt(value.tag() == .unreachable_value);
5182 break :blk .{ .field = id };
5183 },
51845414 else => unreachable,
51855415 };
51865416
......@@ -5765,7 +5995,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
57655995 }
57665996
57675997 if (f.liveness.isUnused(inst)) {
5768 try freeLocal(f, inst, local.local, 0);
5998 try freeLocal(f, inst, local.new_local, 0);
57695999 return CValue.none;
57706000 }
57716001
......@@ -5808,7 +6038,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
58086038 try writer.writeAll(");\n");
58096039
58106040 if (f.liveness.isUnused(inst)) {
5811 try freeLocal(f, inst, local.local, 0);
6041 try freeLocal(f, inst, local.new_local, 0);
58126042 return CValue.none;
58136043 }
58146044
......@@ -5905,7 +6135,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
59056135 try writer.writeAll(";\n");
59066136
59076137 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
5908 try freeLocal(f, inst, index.local, 0);
6138 try freeLocal(f, inst, index.new_local, 0);
59096139
59106140 return CValue.none;
59116141 }
......@@ -6222,7 +6452,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
62226452
62236453 try writer.writeAll(";\n");
62246454
6225 try freeLocal(f, inst, it.local, 0);
6455 try freeLocal(f, inst, it.new_local, 0);
62266456
62276457 return accum;
62286458}
......@@ -6235,8 +6465,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
62356465 const gpa = f.object.dg.gpa;
62366466 const resolved_elements = try gpa.alloc(CValue, elements.len);
62376467 defer gpa.free(resolved_elements);
6238 for (elements, 0..) |element, i| {
6239 resolved_elements[i] = try f.resolveInst(element);
6468 for (resolved_elements, elements) |*resolved_element, element| {
6469 resolved_element.* = try f.resolveInst(element);
62406470 }
62416471 {
62426472 var bt = iterateBigTomb(f, inst);
......@@ -6275,46 +6505,47 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
62756505 try writer.writeAll(")");
62766506 try writer.writeByte('{');
62776507 var empty = true;
6278 for (elements, 0..) |element, index| {
6279 if (inst_ty.structFieldValueComptime(index)) |_| continue;
6508 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6509 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
62806510
62816511 if (!empty) try writer.writeAll(", ");
6282 if (!inst_ty.isTupleOrAnonStruct()) {
6283 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});
6284 }
6512
6513 const field_name: CValue = if (inst_ty.isSimpleTuple())
6514 .{ .field = field_i }
6515 else
6516 .{ .identifier = inst_ty.structFieldName(field_i) };
6517 try writer.writeByte('.');
6518 try f.object.dg.writeCValue(writer, field_name);
6519 try writer.writeAll(" = ");
62856520
62866521 const element_ty = f.air.typeOf(element);
62876522 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
62886523 .Array => CValue{ .undef = element_ty },
6289 else => resolved_elements[index],
6524 else => resolved_element,
62906525 }, .Initializer);
62916526 empty = false;
62926527 }
6293 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
62946528 try writer.writeAll("};\n");
62956529
6296 var field_id: usize = 0;
6297 for (elements, 0..) |element, index| {
6298 if (inst_ty.structFieldValueComptime(index)) |_| continue;
6530 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6531 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
62996532
63006533 const element_ty = f.air.typeOf(element);
63016534 if (element_ty.zigTypeTag() != .Array) continue;
63026535
6303 const field_name = if (inst_ty.isTupleOrAnonStruct())
6304 CValue{ .field = field_id }
6536 const field_name: CValue = if (inst_ty.isSimpleTuple())
6537 .{ .field = field_i }
63056538 else
6306 CValue{ .identifier = inst_ty.structFieldName(index) };
6539 .{ .identifier = inst_ty.structFieldName(field_i) };
63076540
63086541 try writer.writeAll(";\n");
63096542 try writer.writeAll("memcpy(");
63106543 try f.writeCValueMember(writer, local, field_name);
63116544 try writer.writeAll(", ");
6312 try f.writeCValue(writer, resolved_elements[index], .FunctionArgument);
6545 try f.writeCValue(writer, resolved_element, .FunctionArgument);
63136546 try writer.writeAll(", sizeof(");
63146547 try f.renderTypecast(writer, element_ty);
63156548 try writer.writeAll("));\n");
6316
6317 field_id += 1;
63186549 }
63196550 },
63206551 .Packed => {
......@@ -6332,7 +6563,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
63326563 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
63336564
63346565 var empty = true;
6335 for (elements, 0..) |_, index| {
6566 for (0..elements.len) |index| {
63366567 const field_ty = inst_ty.structFieldType(index);
63376568 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
63386569
......@@ -6381,13 +6612,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
63816612 empty = false;
63826613 }
63836614
6384 if (empty) {
6385 try writer.writeByte('(');
6386 try f.renderTypecast(writer, inst_ty);
6387 try writer.writeByte(')');
6388 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
6389 }
6390
63916615 try writer.writeAll(";\n");
63926616 },
63936617 },
......@@ -7020,17 +7244,20 @@ fn isByRef(ty: Type) bool {
70207244}
70217245
70227246const LowerFnRetTyBuffer = struct {
7247 names: [1][]const u8,
70237248 types: [1]Type,
70247249 values: [1]Value,
7025 payload: Type.Payload.Tuple,
7250 payload: Type.Payload.AnonStruct,
70267251};
70277252fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {
70287253 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);
70297254
70307255 if (lowersToArray(ret_ty, target)) {
7256 buffer.names = [1][]const u8{"array"};
70317257 buffer.types = [1]Type{ret_ty};
70327258 buffer.values = [1]Value{Value.initTag(.unreachable_value)};
70337259 buffer.payload = .{ .data = .{
7260 .names = &buffer.names,
70347261 .types = &buffer.types,
70357262 .values = &buffer.values,
70367263 } };
......@@ -7086,7 +7313,7 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
70867313 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
70877314 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
70887315 const local_index = switch (c_value) {
7089 .local => |l| l,
7316 .local, .new_local => |l| l,
70907317 else => return,
70917318 };
70927319 try freeLocal(f, inst, local_index, ref_inst);
......@@ -7161,8 +7388,8 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
71617388}
71627389
71637390fn noticeBranchFrees(f: *Function, pre_locals_len: LocalIndex, inst: Air.Inst.Index) !void {
7164 for (f.locals.items[pre_locals_len..], 0..) |*local, local_offset| {
7165 const local_index = pre_locals_len + @intCast(LocalIndex, local_offset);
7391 for (f.locals.items[pre_locals_len..], pre_locals_len..) |*local, local_i| {
7392 const local_index = @intCast(LocalIndex, local_i);
71667393 if (f.allocs.contains(local_index)) continue; // allocs are not freeable
71677394
71687395 // free more deeply nested locals from other branches at current depth
src/codegen/c/type.zig+707-265
......@@ -110,10 +110,16 @@ pub const CType = extern union {
110110 pointer_const_volatile,
111111 array,
112112 vector,
113 fwd_anon_struct,
114 fwd_anon_union,
113115 fwd_struct,
114116 fwd_union,
117 unnamed_struct,
118 unnamed_union,
119 packed_unnamed_struct,
120 packed_unnamed_union,
115121 anon_struct,
116 packed_anon_struct,
122 anon_union,
117123 @"struct",
118124 @"union",
119125 packed_struct,
......@@ -183,14 +189,22 @@ pub const CType = extern union {
183189 .vector,
184190 => Payload.Sequence,
185191
192 .fwd_anon_struct,
193 .fwd_anon_union,
194 => Payload.Fields,
195
186196 .fwd_struct,
187197 .fwd_union,
188198 => Payload.FwdDecl,
189199
190 .anon_struct,
191 .packed_anon_struct,
192 => Payload.Fields,
200 .unnamed_struct,
201 .unnamed_union,
202 .packed_unnamed_struct,
203 .packed_unnamed_union,
204 => Payload.Unnamed,
193205
206 .anon_struct,
207 .anon_union,
194208 .@"struct",
195209 .@"union",
196210 .packed_struct,
......@@ -229,14 +243,55 @@ pub const CType = extern union {
229243 base: Payload,
230244 data: Data,
231245
232 const Data = []const Field;
233 const Field = struct {
246 pub const Data = []const Field;
247 pub const Field = struct {
234248 name: [*:0]const u8,
235249 type: Index,
236 alignas: u32,
250 alignas: AlignAs,
251 };
252 pub const AlignAs = struct {
253 @"align": std.math.Log2Int(u32),
254 abi: std.math.Log2Int(u32),
255
256 pub fn init(alignment: u32, abi_alignment: u32) AlignAs {
257 assert(std.math.isPowerOfTwo(alignment));
258 assert(std.math.isPowerOfTwo(abi_alignment));
259 return .{
260 .@"align" = std.math.log2_int(u32, alignment),
261 .abi = std.math.log2_int(u32, abi_alignment),
262 };
263 }
264 pub fn abiAlign(ty: Type, target: Target) AlignAs {
265 const abi_align = ty.abiAlignment(target);
266 return init(abi_align, abi_align);
267 }
268 pub fn fieldAlign(struct_ty: Type, field_i: usize, target: Target) AlignAs {
269 return init(
270 struct_ty.structFieldAlign(field_i, target),
271 struct_ty.structFieldType(field_i).abiAlignment(target),
272 );
273 }
274 pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs {
275 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
276 const union_payload_align = union_obj.abiAlignment(target, false);
277 return init(union_payload_align, union_payload_align);
278 }
279
280 pub fn getAlign(self: AlignAs) u32 {
281 return @as(u32, 1) << self.@"align";
282 }
237283 };
238284 };
239285
286 pub const Unnamed = struct {
287 base: Payload,
288 data: struct {
289 fields: Fields.Data,
290 owner_decl: Module.Decl.Index,
291 id: u32,
292 },
293 };
294
240295 pub const Aggregate = struct {
241296 base: Payload,
242297 data: struct {
......@@ -259,22 +314,23 @@ pub const CType = extern union {
259314 arena: std.heap.ArenaAllocator.State = .{},
260315 set: Set = .{},
261316
262 const Set = struct {
263 const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext32, true);
317 pub const Set = struct {
318 pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext32, true);
264319
265320 map: Map = .{},
266321
267 fn indexToCType(self: Set, index: Index) CType {
322 pub fn indexToCType(self: Set, index: Index) CType {
268323 if (index < Tag.no_payload_count) return initTag(@intToEnum(Tag, index));
269324 return self.map.keys()[index - Tag.no_payload_count];
270325 }
271326
272 fn indexToHash(self: Set, index: Index) Map.Hash {
273 if (index < Tag.no_payload_count) return self.indexToCType(index).hash(self);
327 pub fn indexToHash(self: Set, index: Index) Map.Hash {
328 if (index < Tag.no_payload_count)
329 return (HashContext32{ .store = &self }).hash(self.indexToCType(index));
274330 return self.map.entries.items(.hash)[index - Tag.no_payload_count];
275331 }
276332
277 fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {
333 pub fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {
278334 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } };
279335
280336 var convert: Convert = undefined;
......@@ -298,21 +354,27 @@ pub const CType = extern union {
298354 return self.arena.child_allocator;
299355 }
300356
301 fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
357 pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
302358 const t = cty.tag();
303359 if (@enumToInt(t) < Tag.no_payload_count) return @intCast(Index, @enumToInt(t));
304360
305361 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
306362 if (!gop.found_existing) gop.key_ptr.* = cty;
307363 if (std.debug.runtime_safety) {
308 const key = self.set.map.entries.items(.key)[gop.index];
309 assert(key.eql(cty));
364 const key = &self.set.map.entries.items(.key)[gop.index];
365 assert(key == gop.key_ptr);
366 assert(cty.eql(key.*));
310367 assert(cty.hash(self.set) == key.hash(self.set));
311368 }
312369 return @intCast(Index, Tag.no_payload_count + gop.index);
313370 }
314371
315 fn typeToIndex(self: *Promoted, ty: Type, mod: *Module, kind: Kind) Allocator.Error!Index {
372 pub fn typeToIndex(
373 self: *Promoted,
374 ty: Type,
375 mod: *Module,
376 kind: Kind,
377 ) Allocator.Error!Index {
316378 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .mod = mod } };
317379
318380 var convert: Convert = undefined;
......@@ -337,9 +399,10 @@ pub const CType = extern union {
337399 .lookup = lookup.freeze(),
338400 .convert = &convert,
339401 };
340 const key = self.set.map.entries.items(.key)[gop.index];
341 assert(adapter.eql(ty, key));
342 assert(adapter.hash(ty) == key.hash(self.set));
402 const cty = &self.set.map.entries.items(.key)[gop.index];
403 assert(cty == gop.key_ptr);
404 assert(adapter.eql(ty, cty.*));
405 assert(adapter.hash(ty) == cty.hash(self.set));
343406 }
344407 return @intCast(Index, Tag.no_payload_count + gop.index);
345408 }
......@@ -358,21 +421,25 @@ pub const CType = extern union {
358421 return self.set.indexToCType(index);
359422 }
360423
424 pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
425 return self.set.indexToHash(index);
426 }
427
361428 pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
362429 var promoted = self.promote(gpa);
363430 defer self.demote(promoted);
364431 return promoted.cTypeToIndex(cty);
365432 }
366433
367 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module) !CType {
368 const idx = try self.typeToIndex(gpa, ty, mod);
434 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !CType {
435 const idx = try self.typeToIndex(gpa, ty, mod, kind);
369436 return self.indexToCType(idx);
370437 }
371438
372 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module) !Index {
439 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !Index {
373440 var promoted = self.promote(gpa);
374441 defer self.demote(promoted);
375 return promoted.typeToIndex(ty, mod, .complete);
442 return promoted.typeToIndex(ty, mod, kind);
376443 }
377444
378445 pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
......@@ -389,8 +456,16 @@ pub const CType = extern union {
389456 _ = promoted.arena.reset(.free_all);
390457 }
391458
392 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
393 self.set.map.shrinkAndFree(gpa, self.set.map.count());
459 pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
460 self.set.map.shrinkRetainingCapacity(gpa, new_len);
461 }
462
463 pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
464 self.set.map.shrinkAndFree(gpa, new_len);
465 }
466
467 pub fn count(self: Store) usize {
468 return self.set.map.count();
394469 }
395470
396471 pub fn move(self: *Store) Store {
......@@ -407,7 +482,37 @@ pub const CType = extern union {
407482 }
408483 };
409484
485 pub fn isPacked(self: CType) bool {
486 return switch (self.tag()) {
487 else => false,
488 .packed_unnamed_struct,
489 .packed_unnamed_union,
490 .packed_struct,
491 .packed_union,
492 => true,
493 };
494 }
495
496 pub fn fields(self: CType) Payload.Fields.Data {
497 return if (self.cast(Payload.Aggregate)) |pl|
498 pl.data.fields
499 else if (self.cast(Payload.Unnamed)) |pl|
500 pl.data.fields
501 else if (self.cast(Payload.Fields)) |pl|
502 pl.data
503 else
504 unreachable;
505 }
506
410507 pub fn eql(lhs: CType, rhs: CType) bool {
508 return lhs.eqlContext(rhs, struct {
509 pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
510 return lhs_idx == rhs_idx;
511 }
512 }{});
513 }
514
515 pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
411516 // As a shortcut, if the small tags / addresses match, we're done.
412517 if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
413518
......@@ -458,35 +563,52 @@ pub const CType = extern union {
458563 .pointer_const,
459564 .pointer_volatile,
460565 .pointer_const_volatile,
461 => lhs.cast(Payload.Child).?.data == rhs.cast(Payload.Child).?.data,
566 => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
462567
463568 .array,
464569 .vector,
465 => std.meta.eql(lhs.cast(Payload.Sequence).?.data, rhs.cast(Payload.Sequence).?.data),
466
467 .fwd_struct,
468 .fwd_union,
469 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
570 => {
571 const lhs_data = lhs.cast(Payload.Sequence).?.data;
572 const rhs_data = rhs.cast(Payload.Sequence).?.data;
573 return lhs_data.len == rhs_data.len and
574 ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
575 },
470576
471 .anon_struct,
472 .packed_anon_struct,
577 .fwd_anon_struct,
578 .fwd_anon_union,
473579 => {
474580 const lhs_data = lhs.cast(Payload.Fields).?.data;
475581 const rhs_data = rhs.cast(Payload.Fields).?.data;
476582 if (lhs_data.len != rhs_data.len) return false;
477583 for (lhs_data, rhs_data) |lhs_field, rhs_field| {
478 if (lhs_field.type != rhs_field.type) return false;
479 if (lhs_field.alignas != rhs_field.alignas) return false;
584 if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
585 if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
480586 if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false;
481587 }
482588 return true;
483589 },
484590
591 .fwd_struct,
592 .fwd_union,
593 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
594
595 .unnamed_struct,
596 .unnamed_union,
597 .packed_unnamed_struct,
598 .packed_unnamed_union,
599 => {
600 const lhs_data = lhs.cast(Payload.Unnamed).?.data;
601 const rhs_data = rhs.cast(Payload.Unnamed).?.data;
602 return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
603 },
604
605 .anon_struct,
606 .anon_union,
485607 .@"struct",
486608 .@"union",
487609 .packed_struct,
488610 .packed_union,
489 => std.meta.eql(
611 => ctx.eqlIndex(
490612 lhs.cast(Payload.Aggregate).?.data.fwd_decl,
491613 rhs.cast(Payload.Aggregate).?.data.fwd_decl,
492614 ),
......@@ -496,10 +618,10 @@ pub const CType = extern union {
496618 => {
497619 const lhs_data = lhs.cast(Payload.Function).?.data;
498620 const rhs_data = rhs.cast(Payload.Function).?.data;
499 if (lhs_data.return_type != rhs_data.return_type) return false;
500621 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
501 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_cty, rhs_param_cty| {
502 if (lhs_param_cty != rhs_param_cty) return false;
622 if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
623 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
624 if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
503625 }
504626 return true;
505627 },
......@@ -568,18 +690,30 @@ pub const CType = extern union {
568690 store.indexToCType(data.elem_type).updateHasher(hasher, store);
569691 },
570692
693 .fwd_anon_struct,
694 .fwd_anon_union,
695 => for (self.cast(Payload.Fields).?.data) |field| {
696 store.indexToCType(field.type).updateHasher(hasher, store);
697 hasher.update(mem.span(field.name));
698 autoHash(hasher, field.alignas.@"align");
699 },
700
571701 .fwd_struct,
572702 .fwd_union,
573703 => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
574704
575 .anon_struct,
576 .packed_anon_struct,
577 => for (self.cast(Payload.Fields).?.data) |field| {
578 store.indexToCType(field.type).updateHasher(hasher, store);
579 hasher.update(mem.span(field.name));
580 autoHash(hasher, field.alignas);
705 .unnamed_struct,
706 .unnamed_union,
707 .packed_unnamed_struct,
708 .packed_unnamed_union,
709 => {
710 const data = self.cast(Payload.Unnamed).?.data;
711 autoHash(hasher, data.owner_decl);
712 autoHash(hasher, data.id);
581713 },
582714
715 .anon_struct,
716 .anon_union,
583717 .@"struct",
584718 .@"union",
585719 .packed_struct,
......@@ -599,7 +733,7 @@ pub const CType = extern union {
599733 }
600734 }
601735
602 pub const Kind = enum { forward, complete, global, parameter };
736 pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
603737
604738 const Convert = struct {
605739 storage: union {
......@@ -609,9 +743,11 @@ pub const CType = extern union {
609743 fwd: Payload.FwdDecl,
610744 anon: struct {
611745 fields: [2]Payload.Fields.Field,
612 pl: Payload.Fields,
746 pl: union {
747 forward: Payload.Fields,
748 complete: Payload.Aggregate,
749 },
613750 },
614 agg: Payload.Aggregate,
615751 },
616752 value: union(enum) {
617753 tag: Tag,
......@@ -716,6 +852,66 @@ pub const CType = extern union {
716852 }
717853 };
718854
855 fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
856 const Field = Payload.Fields.Field;
857 const slice = self.storage.anon.fields[0..fields_len];
858 std.sort.sort(Field, slice, {}, struct {
859 fn before(_: void, lhs: Field, rhs: Field) bool {
860 return lhs.alignas.@"align" > rhs.alignas.@"align";
861 }
862 }.before);
863 return slice;
864 }
865
866 fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
867 switch (kind) {
868 .forward, .forward_parameter => {
869 self.storage.anon.pl = .{ .forward = .{
870 .base = .{ .tag = .fwd_anon_struct },
871 .data = self.sortFields(fields_len),
872 } };
873 self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
874 },
875 .complete, .parameter, .global => {
876 self.storage.anon.pl = .{ .complete = .{
877 .base = .{ .tag = .anon_struct },
878 .data = .{
879 .fields = self.sortFields(fields_len),
880 .fwd_decl = fwd_idx,
881 },
882 } };
883 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
884 },
885 .payload => unreachable,
886 }
887 }
888
889 fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
890 if (switch (kind) {
891 .forward_parameter => @as(Index, undefined),
892 .parameter => try lookup.typeToIndex(ty, .forward_parameter),
893 .forward, .complete, .global, .payload => unreachable,
894 }) |fwd_idx| {
895 if (try lookup.typeToIndex(ty, switch (kind) {
896 .forward_parameter => .forward,
897 .parameter => .complete,
898 .forward, .complete, .global, .payload => unreachable,
899 })) |array_idx| {
900 self.storage = .{ .anon = undefined };
901 self.storage.anon.fields[0] = .{
902 .name = "array",
903 .type = array_idx,
904 .alignas = Payload.Fields.AlignAs.abiAlign(ty, lookup.getTarget()),
905 };
906 self.initAnon(kind, fwd_idx, 1);
907 } else self.init(switch (kind) {
908 .forward_parameter => .fwd_anon_struct,
909 .parameter => .anon_struct,
910 .forward, .complete, .global, .payload => unreachable,
911 });
912 } else self.init(.anon_struct);
913 }
914
719915 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
720916 const target = lookup.getTarget();
721917
......@@ -739,17 +935,23 @@ pub const CType = extern union {
739935 switch (t) {
740936 .void => unreachable,
741937 else => self.init(t),
742 .array => {
743 const abi_size = ty.abiSize(target);
744 const abi_align = ty.abiAlignment(target);
745 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
746 .len = @divExact(abi_size, abi_align),
747 .elem_type = tagFromIntInfo(
748 .unsigned,
749 @intCast(u16, abi_align * 8),
750 ).toIndex(),
751 } } };
752 self.value = .{ .cty = initPayload(&self.storage.seq) };
938 .array => switch (kind) {
939 .forward, .complete, .global => {
940 const abi_size = ty.abiSize(target);
941 const abi_align = ty.abiAlignment(target);
942 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
943 .len = @divExact(abi_size, abi_align),
944 .elem_type = tagFromIntInfo(
945 .unsigned,
946 @intCast(u16, abi_align * 8),
947 ).toIndex(),
948 } } };
949 self.value = .{ .cty = initPayload(&self.storage.seq) };
950 },
951 .forward_parameter,
952 .parameter,
953 => try self.initArrayParameter(ty, kind, lookup),
954 .payload => unreachable,
753955 },
754956 }
755957 },
......@@ -782,165 +984,297 @@ pub const CType = extern union {
782984 else => unreachable,
783985 }),
784986
785 .Pointer => switch (ty.ptrSize()) {
786 .Slice => {
787 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
788 const ptr_ty = ty.slicePtrFieldType(&buf);
789 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
790 self.storage = .{ .anon = .{ .fields = .{
791 .{
792 .name = "ptr",
793 .type = ptr_idx,
794 .alignas = ptr_ty.abiAlignment(target),
987 .Pointer => {
988 const info = ty.ptrInfo().data;
989 switch (info.size) {
990 .Slice => {
991 if (switch (kind) {
992 .forward, .forward_parameter => @as(Index, undefined),
993 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
994 .payload => unreachable,
995 }) |fwd_idx| {
996 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
997 const ptr_ty = ty.slicePtrFieldType(&buf);
998 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
999 self.storage = .{ .anon = undefined };
1000 self.storage.anon.fields[0] = .{
1001 .name = "ptr",
1002 .type = ptr_idx,
1003 .alignas = Payload.Fields.AlignAs.abiAlign(ptr_ty, target),
1004 };
1005 self.storage.anon.fields[1] = .{
1006 .name = "len",
1007 .type = Tag.uintptr_t.toIndex(),
1008 .alignas = Payload.Fields.AlignAs.abiAlign(Type.usize, target),
1009 };
1010 self.initAnon(kind, fwd_idx, 2);
1011 } else self.init(switch (kind) {
1012 .forward, .forward_parameter => .fwd_anon_struct,
1013 .complete, .parameter, .global => .anon_struct,
1014 .payload => unreachable,
1015 });
1016 } else self.init(.anon_struct);
1017 },
1018
1019 .One, .Many, .C => {
1020 const t: Tag = switch (info.@"volatile") {
1021 false => switch (info.mutable) {
1022 true => .pointer,
1023 false => .pointer_const,
7951024 },
796 .{
797 .name = "len",
798 .type = Tag.size_t.toIndex(),
799 .alignas = Type.usize.abiAlignment(target),
1025 true => switch (info.mutable) {
1026 true => .pointer_volatile,
1027 false => .pointer_const_volatile,
8001028 },
801 }, .pl = undefined } };
802 self.storage.anon.pl = .{
803 .base = .{ .tag = .anon_struct },
804 .data = self.storage.anon.fields[0..2],
8051029 };
806 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };
807 } else self.init(.anon_struct);
808 },
8091030
810 .One, .Many, .C => {
811 const t: Tag = switch (ty.isVolatilePtr()) {
812 false => switch (ty.isConstPtr()) {
813 false => .pointer,
814 true => .pointer_const,
815 },
816 true => switch (ty.isConstPtr()) {
817 false => .pointer_volatile,
818 true => .pointer_const_volatile,
819 },
820 };
821 if (try lookup.typeToIndex(ty.childType(), .forward)) |child_idx| {
822 self.storage = .{ .child = .{ .base = .{ .tag = t }, .data = child_idx } };
823 self.value = .{ .cty = initPayload(&self.storage.child) };
824 } else self.init(t);
825 },
1031 var host_int_pl = Type.Payload.Bits{
1032 .base = .{ .tag = .int_unsigned },
1033 .data = info.host_size * 8,
1034 };
1035 const pointee_ty = if (info.host_size > 0)
1036 Type.initPayload(&host_int_pl.base)
1037 else
1038 info.pointee_type;
1039
1040 if (if (info.size == .C and pointee_ty.tag() == .u8)
1041 Tag.char.toIndex()
1042 else
1043 try lookup.typeToIndex(pointee_ty, .forward)) |child_idx|
1044 {
1045 self.storage = .{ .child = .{
1046 .base = .{ .tag = t },
1047 .data = child_idx,
1048 } };
1049 self.value = .{ .cty = initPayload(&self.storage.child) };
1050 } else self.init(t);
1051 },
1052 }
8261053 },
8271054
828 .Struct, .Union => |zig_tag| if (ty.isTupleOrAnonStruct()) {
1055 .Struct, .Union => |zig_tag| if (ty.containerLayout() == .Packed) {
1056 if (ty.castTag(.@"struct")) |struct_obj| {
1057 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
1058 } else {
1059 var buf: Type.Payload.Bits = .{
1060 .base = .{ .tag = .int_unsigned },
1061 .data = @intCast(u16, ty.bitSize(target)),
1062 };
1063 try self.initType(Type.initPayload(&buf.base), kind, lookup);
1064 }
1065 } else if (ty.isTupleOrAnonStruct()) {
8291066 if (lookup.isMutable()) {
8301067 for (0..ty.structFieldCount()) |field_i| {
8311068 const field_ty = ty.structFieldType(field_i);
8321069 if (ty.structFieldIsComptime(field_i) or
8331070 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
8341071 _ = try lookup.typeToIndex(field_ty, switch (kind) {
835 .forward, .complete, .parameter => .complete,
1072 .forward, .forward_parameter => .forward,
1073 .complete, .parameter => .complete,
8361074 .global => .global,
1075 .payload => unreachable,
8371076 });
8381077 }
1078 switch (kind) {
1079 .forward, .forward_parameter => {},
1080 .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
1081 .payload => unreachable,
1082 }
8391083 }
840 self.init(.anon_struct);
1084 self.init(switch (kind) {
1085 .forward, .forward_parameter => .fwd_anon_struct,
1086 .complete, .parameter, .global => .anon_struct,
1087 .payload => unreachable,
1088 });
8411089 } else {
842 const is_struct = zig_tag == .Struct or ty.unionTagTypeSafety() != null;
1090 const tag_ty = ty.unionTagTypeSafety();
1091 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1092 const is_struct = zig_tag == .Struct or is_tagged_union_wrapper;
8431093 switch (kind) {
844 .forward => {
1094 .forward, .forward_parameter => {
8451095 self.storage = .{ .fwd = .{
8461096 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
8471097 .data = ty.getOwnerDecl(),
8481098 } };
8491099 self.value = .{ .cty = initPayload(&self.storage.fwd) };
8501100 },
851 else => {
852 if (lookup.isMutable()) {
853 for (0..switch (zig_tag) {
854 .Struct => ty.structFieldCount(),
855 .Union => ty.cast(Type.Payload.Union).?.data.fields.count(),
856 else => unreachable,
857 }) |field_i| {
858 const field_ty = ty.structFieldType(field_i);
859 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1101 .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
1102 const fwd_idx = try lookup.typeToIndex(ty, .forward);
1103 const payload_idx = try lookup.typeToIndex(ty, .payload);
1104 const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
1105 if (fwd_idx != null and payload_idx != null and tag_idx != null) {
1106 self.storage = .{ .anon = undefined };
1107 var field_count: usize = 0;
1108 if (payload_idx != Tag.void.toIndex()) {
1109 self.storage.anon.fields[field_count] = .{
1110 .name = "payload",
1111 .type = payload_idx.?,
1112 .alignas = Payload.Fields.AlignAs.unionPayloadAlign(ty, target),
1113 };
1114 field_count += 1;
1115 }
1116 if (tag_idx != Tag.void.toIndex()) {
1117 self.storage.anon.fields[field_count] = .{
1118 .name = "tag",
1119 .type = tag_idx.?,
1120 .alignas = Payload.Fields.AlignAs.abiAlign(tag_ty.?, target),
1121 };
1122 field_count += 1;
1123 }
1124 self.storage.anon.pl = .{ .complete = .{
1125 .base = .{ .tag = .@"struct" },
1126 .data = .{
1127 .fields = self.sortFields(field_count),
1128 .fwd_decl = fwd_idx.?,
1129 },
1130 } };
1131 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
1132 } else self.init(.@"struct");
1133 } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) {
1134 self.init(.void);
1135 } else {
1136 var is_packed = false;
1137 for (0..switch (zig_tag) {
1138 .Struct => ty.structFieldCount(),
1139 .Union => ty.unionFields().count(),
1140 else => unreachable,
1141 }) |field_i| {
1142 const field_ty = ty.structFieldType(field_i);
1143 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1144
1145 const field_align = Payload.Fields.AlignAs.fieldAlign(
1146 ty,
1147 field_i,
1148 target,
1149 );
1150 if (field_align.@"align" < field_align.abi) {
1151 is_packed = true;
1152 if (!lookup.isMutable()) break;
1153 }
1154
1155 if (lookup.isMutable()) {
8601156 _ = try lookup.typeToIndex(field_ty, switch (kind) {
861 .forward => unreachable,
862 .complete, .parameter => .complete,
1157 .forward, .forward_parameter => unreachable,
1158 .complete, .parameter, .payload => .complete,
8631159 .global => .global,
8641160 });
8651161 }
866 _ = try lookup.typeToIndex(ty, .forward);
8671162 }
868 self.init(if (is_struct) .@"struct" else .@"union");
1163 switch (kind) {
1164 .forward, .forward_parameter => unreachable,
1165 .complete, .parameter, .global => {
1166 _ = try lookup.typeToIndex(ty, .forward);
1167 self.init(if (is_struct)
1168 if (is_packed) .packed_struct else .@"struct"
1169 else if (is_packed) .packed_union else .@"union");
1170 },
1171 .payload => self.init(if (is_packed)
1172 .packed_unnamed_union
1173 else
1174 .unnamed_union),
1175 }
8691176 },
8701177 }
8711178 },
8721179
8731180 .Array, .Vector => |zig_tag| {
874 const t: Tag = switch (zig_tag) {
875 .Array => .array,
876 .Vector => .vector,
877 else => unreachable,
878 };
879 if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {
880 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
881 .len = ty.arrayLenIncludingSentinel(),
882 .elem_type = child_idx,
883 } } };
884 self.value = .{ .cty = initPayload(&self.storage.seq) };
885 } else self.init(t);
1181 switch (kind) {
1182 .forward, .complete, .global => {
1183 const t: Tag = switch (zig_tag) {
1184 .Array => .array,
1185 .Vector => .vector,
1186 else => unreachable,
1187 };
1188 if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {
1189 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
1190 .len = ty.arrayLenIncludingSentinel(),
1191 .elem_type = child_idx,
1192 } } };
1193 self.value = .{ .cty = initPayload(&self.storage.seq) };
1194 } else self.init(t);
1195 },
1196 .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
1197 .payload => unreachable,
1198 }
8861199 },
8871200
8881201 .Optional => {
8891202 var buf: Type.Payload.ElemType = undefined;
8901203 const payload_ty = ty.optionalChild(&buf);
8911204 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
892 if (ty.optionalReprIsPayload())
893 try self.initType(payload_ty, kind, lookup)
894 else if (try lookup.typeToIndex(payload_ty, kind)) |payload_idx| {
895 self.storage = .{ .anon = .{ .fields = .{
896 .{
1205 if (ty.optionalReprIsPayload()) {
1206 try self.initType(payload_ty, kind, lookup);
1207 } else if (switch (kind) {
1208 .forward, .forward_parameter => @as(Index, undefined),
1209 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1210 .payload => unreachable,
1211 }) |fwd_idx| {
1212 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1213 .forward, .forward_parameter => .forward,
1214 .complete, .parameter => .complete,
1215 .global => .global,
1216 .payload => unreachable,
1217 })) |payload_idx| {
1218 self.storage = .{ .anon = undefined };
1219 self.storage.anon.fields[0] = .{
8971220 .name = "payload",
8981221 .type = payload_idx,
899 .alignas = payload_ty.abiAlignment(target),
900 },
901 .{
1222 .alignas = Payload.Fields.AlignAs.abiAlign(payload_ty, target),
1223 };
1224 self.storage.anon.fields[1] = .{
9021225 .name = "is_null",
9031226 .type = Tag.bool.toIndex(),
904 .alignas = Type.bool.abiAlignment(target),
905 },
906 }, .pl = undefined } };
907 self.storage.anon.pl = .{
908 .base = .{ .tag = .anon_struct },
909 .data = self.storage.anon.fields[0..2],
910 };
911 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };
1227 .alignas = Payload.Fields.AlignAs.abiAlign(Type.bool, target),
1228 };
1229 self.initAnon(kind, fwd_idx, 2);
1230 } else self.init(switch (kind) {
1231 .forward, .forward_parameter => .fwd_anon_struct,
1232 .complete, .parameter, .global => .anon_struct,
1233 .payload => unreachable,
1234 });
9121235 } else self.init(.anon_struct);
9131236 } else self.init(.bool);
9141237 },
9151238
9161239 .ErrorUnion => {
917 const payload_ty = ty.errorUnionPayload();
918 if (try lookup.typeToIndex(payload_ty, switch (kind) {
919 .forward, .complete, .parameter => .complete,
920 .global => .global,
921 })) |payload_idx| {
922 const error_ty = ty.errorUnionSet();
923 if (payload_idx == Tag.void.toIndex())
924 try self.initType(error_ty, kind, lookup)
925 else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
926 self.storage = .{ .anon = .{ .fields = .{
927 .{
1240 if (switch (kind) {
1241 .forward, .forward_parameter => @as(Index, undefined),
1242 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1243 .payload => unreachable,
1244 }) |fwd_idx| {
1245 const payload_ty = ty.errorUnionPayload();
1246 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1247 .forward, .forward_parameter => .forward,
1248 .complete, .parameter => .complete,
1249 .global => .global,
1250 .payload => unreachable,
1251 })) |payload_idx| {
1252 const error_ty = ty.errorUnionSet();
1253 if (payload_idx == Tag.void.toIndex()) {
1254 try self.initType(error_ty, kind, lookup);
1255 } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
1256 self.storage = .{ .anon = undefined };
1257 self.storage.anon.fields[0] = .{
9281258 .name = "payload",
9291259 .type = payload_idx,
930 .alignas = payload_ty.abiAlignment(target),
931 },
932 .{
1260 .alignas = Payload.Fields.AlignAs.abiAlign(payload_ty, target),
1261 };
1262 self.storage.anon.fields[1] = .{
9331263 .name = "error",
9341264 .type = error_idx,
935 .alignas = error_ty.abiAlignment(target),
936 },
937 }, .pl = undefined } };
938 self.storage.anon.pl = .{
939 .base = .{ .tag = .anon_struct },
940 .data = self.storage.anon.fields[0..2],
941 };
942 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };
943 } else self.init(.anon_struct);
1265 .alignas = Payload.Fields.AlignAs.abiAlign(error_ty, target),
1266 };
1267 self.initAnon(kind, fwd_idx, 2);
1268 } else self.init(switch (kind) {
1269 .forward, .forward_parameter => .fwd_anon_struct,
1270 .complete, .parameter, .global => .anon_struct,
1271 .payload => unreachable,
1272 });
1273 } else self.init(switch (kind) {
1274 .forward, .forward_parameter => .fwd_anon_struct,
1275 .complete, .parameter, .global => .anon_struct,
1276 .payload => unreachable,
1277 });
9441278 } else self.init(.anon_struct);
9451279 },
9461280
......@@ -959,16 +1293,15 @@ pub const CType = extern union {
9591293 .Fn => {
9601294 const info = ty.fnInfo();
9611295 if (lookup.isMutable()) {
962 _ = try lookup.typeToIndex(info.return_type, switch (kind) {
963 .forward => .forward,
964 .complete, .parameter, .global => .complete,
965 });
1296 const param_kind: Kind = switch (kind) {
1297 .forward, .forward_parameter => .forward_parameter,
1298 .complete, .parameter, .global => .parameter,
1299 .payload => unreachable,
1300 };
1301 _ = try lookup.typeToIndex(info.return_type, param_kind);
9661302 for (info.param_types) |param_type| {
9671303 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
968 _ = try lookup.typeToIndex(param_type, switch (kind) {
969 .forward => .forward,
970 .complete, .parameter, .global => unreachable,
971 });
1304 _ = try lookup.typeToIndex(param_type, param_kind);
9721305 }
9731306 }
9741307 self.init(if (info.is_var_args) .varargs_function else .function);
......@@ -977,16 +1310,33 @@ pub const CType = extern union {
9771310 }
9781311 };
9791312
980 fn copyFields(arena: Allocator, fields: Payload.Fields.Data) !Payload.Fields.Data {
981 const new_fields = try arena.dupe(Payload.Fields.Field, fields);
982 for (new_fields) |*new_field| {
983 new_field.name = try arena.dupeZ(u8, mem.span(new_field.name));
984 new_field.type = new_field.type;
1313 pub fn copy(self: CType, arena: Allocator) !CType {
1314 return self.copyContext(struct {
1315 arena: Allocator,
1316 pub fn copyIndex(_: @This(), idx: Index) Index {
1317 return idx;
1318 }
1319 }{ .arena = arena });
1320 }
1321
1322 fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
1323 const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
1324 for (new_fields, old_fields) |*new_field, old_field| {
1325 new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
1326 new_field.type = ctx.copyIndex(old_field.type);
1327 new_field.alignas = old_field.alignas;
9851328 }
9861329 return new_fields;
9871330 }
9881331
989 pub fn copy(self: CType, arena: Allocator) !CType {
1332 fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
1333 const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
1334 for (new_param_types, old_param_types) |*new_param_type, old_param_type|
1335 new_param_type.* = ctx.copyIndex(old_param_type);
1336 return new_param_types;
1337 }
1338
1339 pub fn copyContext(self: CType, ctx: anytype) !CType {
9901340 switch (self.tag()) {
9911341 .void,
9921342 .char,
......@@ -1032,8 +1382,8 @@ pub const CType = extern union {
10321382 .pointer_const_volatile,
10331383 => {
10341384 const pl = self.cast(Payload.Child).?;
1035 const new_pl = try arena.create(Payload.Child);
1036 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
1385 const new_pl = try ctx.arena.create(Payload.Child);
1386 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
10371387 return initPayload(new_pl);
10381388 },
10391389
......@@ -1041,48 +1391,62 @@ pub const CType = extern union {
10411391 .vector,
10421392 => {
10431393 const pl = self.cast(Payload.Sequence).?;
1044 const new_pl = try arena.create(Payload.Sequence);
1394 const new_pl = try ctx.arena.create(Payload.Sequence);
10451395 new_pl.* = .{
10461396 .base = .{ .tag = pl.base.tag },
1047 .data = .{ .len = pl.data.len, .elem_type = pl.data.elem_type },
1397 .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
10481398 };
10491399 return initPayload(new_pl);
10501400 },
10511401
1052 .fwd_struct,
1053 .fwd_union,
1402 .fwd_anon_struct,
1403 .fwd_anon_union,
10541404 => {
1055 const pl = self.cast(Payload.FwdDecl).?;
1056 const new_pl = try arena.create(Payload.FwdDecl);
1405 const pl = self.cast(Payload.Fields).?;
1406 const new_pl = try ctx.arena.create(Payload.Fields);
10571407 new_pl.* = .{
10581408 .base = .{ .tag = pl.base.tag },
1059 .data = pl.data,
1409 .data = try copyFields(ctx, pl.data),
10601410 };
10611411 return initPayload(new_pl);
10621412 },
10631413
1064 .anon_struct,
1065 .packed_anon_struct,
1414 .fwd_struct,
1415 .fwd_union,
10661416 => {
1067 const pl = self.cast(Payload.Fields).?;
1068 const new_pl = try arena.create(Payload.Fields);
1069 new_pl.* = .{
1070 .base = .{ .tag = pl.base.tag },
1071 .data = try copyFields(arena, pl.data),
1072 };
1417 const pl = self.cast(Payload.FwdDecl).?;
1418 const new_pl = try ctx.arena.create(Payload.FwdDecl);
1419 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
1420 return initPayload(new_pl);
1421 },
1422
1423 .unnamed_struct,
1424 .unnamed_union,
1425 .packed_unnamed_struct,
1426 .packed_unnamed_union,
1427 => {
1428 const pl = self.cast(Payload.Unnamed).?;
1429 const new_pl = try ctx.arena.create(Payload.Unnamed);
1430 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1431 .fields = try copyFields(ctx, pl.data.fields),
1432 .owner_decl = pl.data.owner_decl,
1433 .id = pl.data.id,
1434 } };
10731435 return initPayload(new_pl);
10741436 },
10751437
1438 .anon_struct,
1439 .anon_union,
10761440 .@"struct",
10771441 .@"union",
10781442 .packed_struct,
10791443 .packed_union,
10801444 => {
10811445 const pl = self.cast(Payload.Aggregate).?;
1082 const new_pl = try arena.create(Payload.Aggregate);
1446 const new_pl = try ctx.arena.create(Payload.Aggregate);
10831447 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1084 .fields = try copyFields(arena, pl.data.fields),
1085 .fwd_decl = pl.data.fwd_decl,
1448 .fields = try copyFields(ctx, pl.data.fields),
1449 .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
10861450 } };
10871451 return initPayload(new_pl);
10881452 },
......@@ -1091,10 +1455,10 @@ pub const CType = extern union {
10911455 .varargs_function,
10921456 => {
10931457 const pl = self.cast(Payload.Function).?;
1094 const new_pl = try arena.create(Payload.Function);
1458 const new_pl = try ctx.arena.create(Payload.Function);
10951459 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1096 .return_type = pl.data.return_type,
1097 .param_types = try arena.dupe(Index, pl.data.param_types),
1460 .return_type = ctx.copyIndex(pl.data.return_type),
1461 .param_types = try copyParams(ctx, pl.data.param_types),
10981462 } };
10991463 return initPayload(new_pl);
11001464 },
......@@ -1118,8 +1482,14 @@ pub const CType = extern union {
11181482 switch (convert.value) {
11191483 .cty => |c| return c.copy(arena),
11201484 .tag => |t| switch (t) {
1485 .fwd_anon_struct,
1486 .fwd_anon_union,
1487 .unnamed_struct,
1488 .unnamed_union,
1489 .packed_unnamed_struct,
1490 .packed_unnamed_union,
11211491 .anon_struct,
1122 .packed_anon_struct,
1492 .anon_union,
11231493 .@"struct",
11241494 .@"union",
11251495 .packed_struct,
......@@ -1149,31 +1519,44 @@ pub const CType = extern union {
11491519 else
11501520 arena.dupeZ(u8, ty.structFieldName(field_i)),
11511521 .type = store.set.typeToIndex(field_ty, target, switch (kind) {
1152 .forward, .complete, .parameter => .complete,
1522 .forward, .forward_parameter => .forward,
1523 .complete, .parameter => .complete,
11531524 .global => .global,
1525 .payload => unreachable,
11541526 }).?,
1155 .alignas = ty.structFieldAlign(field_i, target),
1527 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
11561528 };
11571529 c_field_i += 1;
11581530 }
11591531
1160 if (ty.isTupleOrAnonStruct()) {
1161 const anon_pl = try arena.create(Payload.Fields);
1162 anon_pl.* = .{ .base = .{ .tag = .anon_struct }, .data = fields_pl };
1163 return initPayload(anon_pl);
1164 }
1532 switch (t) {
1533 .fwd_anon_struct => {
1534 const anon_pl = try arena.create(Payload.Fields);
1535 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
1536 return initPayload(anon_pl);
1537 },
11651538
1166 const struct_pl = try arena.create(Payload.Aggregate);
1167 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1168 .fields = fields_pl,
1169 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1170 } };
1171 return initPayload(struct_pl);
1539 .anon_struct,
1540 .@"struct",
1541 .@"union",
1542 .packed_struct,
1543 .packed_union,
1544 => {
1545 const struct_pl = try arena.create(Payload.Aggregate);
1546 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1547 .fields = fields_pl,
1548 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1549 } };
1550 return initPayload(struct_pl);
1551 },
1552
1553 else => unreachable,
1554 }
11721555 },
11731556
11741557 .Union => {
1175 const fields = ty.unionFields();
1176 const fields_len = fields.count();
1558 const union_fields = ty.unionFields();
1559 const fields_len = union_fields.count();
11771560
11781561 var c_fields_len: usize = 0;
11791562 for (0..fields_len) |field_i| {
......@@ -1185,7 +1568,7 @@ pub const CType = extern union {
11851568 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
11861569 var field_i: usize = 0;
11871570 var c_field_i: usize = 0;
1188 var field_it = fields.iterator();
1571 var field_it = union_fields.iterator();
11891572 while (field_it.next()) |field| {
11901573 defer field_i += 1;
11911574 if (!field.value_ptr.ty.hasRuntimeBitsIgnoreComptime()) continue;
......@@ -1193,21 +1576,35 @@ pub const CType = extern union {
11931576 fields_pl[c_field_i] = .{
11941577 .name = try arena.dupeZ(u8, field.key_ptr.*),
11951578 .type = store.set.typeToIndex(field.value_ptr.ty, target, switch (kind) {
1196 .forward => unreachable,
1197 .complete, .parameter => .complete,
1579 .forward, .forward_parameter => unreachable,
1580 .complete, .parameter, .payload => .complete,
11981581 .global => .global,
11991582 }).?,
1200 .alignas = ty.structFieldAlign(field_i, target),
1583 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
12011584 };
12021585 c_field_i += 1;
12031586 }
12041587
1205 const union_pl = try arena.create(Payload.Aggregate);
1206 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1207 .fields = fields_pl,
1208 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1209 } };
1210 return initPayload(union_pl);
1588 switch (kind) {
1589 .forward, .forward_parameter => unreachable,
1590 .complete, .parameter, .global => {
1591 const union_pl = try arena.create(Payload.Aggregate);
1592 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1593 .fields = fields_pl,
1594 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1595 } };
1596 return initPayload(union_pl);
1597 },
1598 .payload => if (ty.unionTagTypeSafety()) |_| {
1599 const union_pl = try arena.create(Payload.Unnamed);
1600 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1601 .fields = fields_pl,
1602 .owner_decl = ty.getOwnerDecl(),
1603 .id = 0,
1604 } };
1605 return initPayload(union_pl);
1606 } else unreachable,
1607 }
12111608 },
12121609
12131610 else => unreachable,
......@@ -1217,9 +1614,10 @@ pub const CType = extern union {
12171614 .varargs_function,
12181615 => {
12191616 const info = ty.fnInfo();
1220 const recurse_kind: Kind = switch (kind) {
1221 .forward => .forward,
1222 .complete, .parameter, .global => unreachable,
1617 const param_kind: Kind = switch (kind) {
1618 .forward, .forward_parameter => .forward_parameter,
1619 .complete, .parameter, .global => .parameter,
1620 .payload => unreachable,
12231621 };
12241622
12251623 var c_params_len: usize = 0;
......@@ -1232,13 +1630,13 @@ pub const CType = extern union {
12321630 var c_param_i: usize = 0;
12331631 for (info.param_types) |param_type| {
12341632 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1235 params_pl[c_param_i] = store.set.typeToIndex(param_type, target, recurse_kind).?;
1633 params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?;
12361634 c_param_i += 1;
12371635 }
12381636
12391637 const fn_pl = try arena.create(Payload.Function);
12401638 fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
1241 .return_type = store.set.typeToIndex(info.return_type, target, recurse_kind).?,
1639 .return_type = store.set.typeToIndex(info.return_type, target, param_kind).?,
12421640 .param_types = params_pl,
12431641 } };
12441642 return initPayload(fn_pl);
......@@ -1294,8 +1692,8 @@ pub const CType = extern union {
12941692
12951693 const target = self.lookup.getTarget();
12961694 switch (t) {
1297 .anon_struct,
1298 .packed_anon_struct,
1695 .fwd_anon_struct,
1696 .fwd_anon_union,
12991697 => {
13001698 if (!ty.isTupleOrAnonStruct()) return false;
13011699
......@@ -1313,26 +1711,38 @@ pub const CType = extern union {
13131711 const c_field = &c_fields[c_field_i];
13141712 c_field_i += 1;
13151713
1316 if (!self.eqlRecurse(
1317 ty.structFieldType(field_i),
1318 c_field.type,
1319 switch (self.kind) {
1320 .forward, .complete, .parameter => .complete,
1321 .global => .global,
1322 },
1323 ) or !mem.eql(
1714 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
1715 .forward, .forward_parameter => .forward,
1716 .complete, .parameter => .complete,
1717 .global => .global,
1718 .payload => unreachable,
1719 }) or !mem.eql(
13241720 u8,
13251721 if (ty.isSimpleTuple())
13261722 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
13271723 else
13281724 ty.structFieldName(field_i),
13291725 mem.span(c_field.name),
1330 ) or ty.structFieldAlign(field_i, target) != c_field.alignas)
1331 return false;
1726 ) or Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align" !=
1727 c_field.alignas.@"align") return false;
13321728 }
13331729 return true;
13341730 },
13351731
1732 .unnamed_struct,
1733 .unnamed_union,
1734 .packed_unnamed_struct,
1735 .packed_unnamed_union,
1736 => switch (self.kind) {
1737 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1738 .payload => if (ty.unionTagTypeSafety()) |_| {
1739 const data = cty.cast(Payload.Unnamed).?.data;
1740 return ty.getOwnerDecl() == data.owner_decl and data.id == 0;
1741 } else unreachable,
1742 },
1743
1744 .anon_struct,
1745 .anon_union,
13361746 .@"struct",
13371747 .@"union",
13381748 .packed_struct,
......@@ -1350,19 +1760,27 @@ pub const CType = extern union {
13501760
13511761 const info = ty.fnInfo();
13521762 const data = cty.cast(Payload.Function).?.data;
1353 const recurse_kind: Kind = switch (self.kind) {
1354 .forward => .forward,
1355 .complete, .parameter, .global => unreachable,
1763 const param_kind: Kind = switch (self.kind) {
1764 .forward, .forward_parameter => .forward_parameter,
1765 .complete, .parameter, .global => .parameter,
1766 .payload => unreachable,
13561767 };
13571768
1358 if (info.param_types.len != data.param_types.len or
1359 !self.eqlRecurse(info.return_type, data.return_type, recurse_kind))
1769 if (!self.eqlRecurse(info.return_type, data.return_type, param_kind))
13601770 return false;
1361 for (info.param_types, data.param_types) |param_ty, param_cty| {
1362 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
1363 if (!self.eqlRecurse(param_ty, param_cty, recurse_kind)) return false;
1771
1772 var c_param_i: usize = 0;
1773 for (info.param_types) |param_type| {
1774 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1775
1776 if (c_param_i >= data.param_types.len) return false;
1777 const param_cty = data.param_types[c_param_i];
1778 c_param_i += 1;
1779
1780 if (!self.eqlRecurse(param_type, param_cty, param_kind))
1781 return false;
13641782 }
1365 return true;
1783 return c_param_i == data.param_types.len;
13661784 },
13671785
13681786 else => unreachable,
......@@ -1395,13 +1813,17 @@ pub const CType = extern union {
13951813
13961814 const target = self.lookup.getTarget();
13971815 switch (t) {
1398 .anon_struct,
1399 .packed_anon_struct,
1816 .fwd_anon_struct,
1817 .fwd_anon_union,
14001818 => {
14011819 var name_buf: [
14021820 std.fmt.count("f{}", .{std.math.maxInt(usize)})
14031821 ]u8 = undefined;
1404 for (0..ty.structFieldCount()) |field_i| {
1822 for (0..switch (ty.zigTypeTag()) {
1823 .Struct => ty.structFieldCount(),
1824 .Union => ty.unionFields().count(),
1825 else => unreachable,
1826 }) |field_i| {
14051827 const field_ty = ty.structFieldType(field_i);
14061828 if (ty.structFieldIsComptime(field_i) or
14071829 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
......@@ -1410,18 +1832,37 @@ pub const CType = extern union {
14101832 hasher,
14111833 ty.structFieldType(field_i),
14121834 switch (self.kind) {
1413 .forward, .complete, .parameter => .complete,
1835 .forward, .forward_parameter => .forward,
1836 .complete, .parameter => .complete,
14141837 .global => .global,
1838 .payload => unreachable,
14151839 },
14161840 );
14171841 hasher.update(if (ty.isSimpleTuple())
14181842 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
14191843 else
14201844 ty.structFieldName(field_i));
1421 autoHash(hasher, ty.structFieldAlign(field_i, target));
1845 autoHash(
1846 hasher,
1847 Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align",
1848 );
14221849 }
14231850 },
14241851
1852 .unnamed_struct,
1853 .unnamed_union,
1854 .packed_unnamed_struct,
1855 .packed_unnamed_union,
1856 => switch (self.kind) {
1857 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1858 .payload => if (ty.unionTagTypeSafety()) |_| {
1859 autoHash(hasher, ty.getOwnerDecl());
1860 autoHash(hasher, @as(u32, 0));
1861 } else unreachable,
1862 },
1863
1864 .anon_struct,
1865 .anon_union,
14251866 .@"struct",
14261867 .@"union",
14271868 .packed_struct,
......@@ -1432,15 +1873,16 @@ pub const CType = extern union {
14321873 .varargs_function,
14331874 => {
14341875 const info = ty.fnInfo();
1435 const recurse_kind: Kind = switch (self.kind) {
1436 .forward => .forward,
1437 .complete, .parameter, .global => unreachable,
1876 const param_kind: Kind = switch (self.kind) {
1877 .forward, .forward_parameter => .forward_parameter,
1878 .complete, .parameter, .global => .parameter,
1879 .payload => unreachable,
14381880 };
14391881
1440 self.updateHasherRecurse(hasher, info.return_type, recurse_kind);
1882 self.updateHasherRecurse(hasher, info.return_type, param_kind);
14411883 for (info.param_types) |param_type| {
14421884 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1443 self.updateHasherRecurse(hasher, param_type, recurse_kind);
1885 self.updateHasherRecurse(hasher, param_type, param_kind);
14441886 }
14451887 },
14461888
src/link/C.zig+137-50
......@@ -117,7 +117,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
117117 .gpa = gpa,
118118 .module = module,
119119 .error_msg = null,
120 .decl_index = decl_index,
120 .decl_index = decl_index.toOptional(),
121121 .decl = module.declPtr(decl_index),
122122 .fwd_decl = fwd_decl.toManaged(gpa),
123123 .ctypes = ctypes.*,
......@@ -146,7 +146,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
146146 code.* = function.object.code.moveToUnmanaged();
147147
148148 // Free excess allocated memory for this Decl.
149 ctypes.shrinkToFit(gpa);
149 ctypes.shrinkAndFree(gpa, ctypes.count());
150150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
151151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
152152 code.shrinkAndFree(gpa, code.items.len);
......@@ -176,7 +176,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
176176 .gpa = gpa,
177177 .module = module,
178178 .error_msg = null,
179 .decl_index = decl_index,
179 .decl_index = decl_index.toOptional(),
180180 .decl = decl,
181181 .fwd_decl = fwd_decl.toManaged(gpa),
182182 .ctypes = ctypes.*,
......@@ -204,7 +204,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
204204 code.* = object.code.moveToUnmanaged();
205205
206206 // Free excess allocated memory for this Decl.
207 ctypes.shrinkToFit(gpa);
207 ctypes.shrinkAndFree(gpa, ctypes.count());
208208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
209209 code.shrinkAndFree(gpa, code.items.len);
210210}
......@@ -247,8 +247,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
247247
248248 const abi_define = abiDefine(comp);
249249
250 // Covers defines, zig.h, ctypes, asm.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 4);
250 // Covers defines, zig.h, ctypes, asm, lazy fwd, lazy code.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 6);
252252
253253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
254254 f.appendBufAssumeCapacity(zig_h);
......@@ -258,15 +258,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
258258
259259 {
260260 var asm_buf = f.asm_buf.toManaged(gpa);
261 defer asm_buf.deinit();
262
263 try codegen.genGlobalAsm(module, &asm_buf);
264
265 f.asm_buf = asm_buf.moveToUnmanaged();
266 f.appendBufAssumeCapacity(f.asm_buf.items);
261 defer f.asm_buf = asm_buf.moveToUnmanaged();
262 try codegen.genGlobalAsm(module, asm_buf.writer());
263 f.appendBufAssumeCapacity(asm_buf.items);
267264 }
268265
269 try self.flushErrDecls(&f);
266 const lazy_indices = f.all_buffers.items.len;
267 f.all_buffers.items.len += 2;
268
269 try self.flushErrDecls(&f.lazy_db);
270270
271271 // `CType`s, forward decls, and non-functions first.
272272 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore
......@@ -295,6 +295,30 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
295295 }
296296 }
297297
298 {
299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
300 assert(f.ctypes.count() == 0);
301 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);
302
303 var it = self.decl_table.iterator();
304 while (it.next()) |entry|
305 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
306 }
307
308 {
309 f.all_buffers.items[lazy_indices + 0] = .{
310 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
311 .iov_len = f.lazy_db.fwd_decl.items.len,
312 };
313 f.file_size += f.lazy_db.fwd_decl.items.len;
314
315 f.all_buffers.items[lazy_indices + 1] = .{
316 .iov_base = if (f.lazy_db.code.items.len > 0) f.lazy_db.code.items.ptr else "",
317 .iov_len = f.lazy_db.code.items.len,
318 };
319 f.file_size += f.lazy_db.code.items.len;
320 }
321
298322 f.all_buffers.items[ctypes_index] = .{
299323 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
300324 .iov_len = f.ctypes_buf.items.len,
......@@ -318,17 +342,17 @@ const Flush = struct {
318342 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
319343 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
320344
321 err_decls: DeclBlock = .{},
322
345 lazy_db: DeclBlock = .{},
323346 lazy_fns: LazyFns = .{},
324347
325348 asm_buf: std.ArrayListUnmanaged(u8) = .{},
349
326350 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
327351 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
328352 /// Keeps track of the total bytes of `all_buffers`.
329353 file_size: u64 = 0,
330354
331 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, DeclBlock);
355 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
332356
333357 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
334358 if (buf.len == 0) return;
......@@ -338,10 +362,9 @@ const Flush = struct {
338362
339363 fn deinit(f: *Flush, gpa: Allocator) void {
340364 f.all_buffers.deinit(gpa);
341 var lazy_fns_it = f.lazy_fns.valueIterator();
342 while (lazy_fns_it.next()) |db| db.deinit(gpa);
365 f.asm_buf.deinit(gpa);
343366 f.lazy_fns.deinit(gpa);
344 f.err_decls.deinit(gpa);
367 f.lazy_db.deinit(gpa);
345368 f.ctypes_buf.deinit(gpa);
346369 f.ctypes_map.deinit(gpa);
347370 f.ctypes.deinit(gpa);
......@@ -353,26 +376,106 @@ const FlushDeclError = error{
353376 OutOfMemory,
354377};
355378
356fn flushCTypes(self: *C, f: *Flush, ctypes: codegen.CType.Store) FlushDeclError!void {
357 _ = self;
358 _ = f;
359 _ = ctypes;
379fn flushCTypes(
380 self: *C,
381 f: *Flush,
382 decl_index: Module.Decl.OptionalIndex,
383 decl_ctypes: codegen.CType.Store,
384) FlushDeclError!void {
385 const gpa = self.base.allocator;
386 const mod = self.base.options.module.?;
387
388 const decl_ctypes_len = decl_ctypes.count();
389 f.ctypes_map.clearRetainingCapacity();
390 try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);
391
392 var global_ctypes = f.ctypes.promote(gpa);
393 defer f.ctypes.demote(global_ctypes);
394
395 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
396 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
397 const writer = ctypes_buf.writer();
398
399 const slice = decl_ctypes.set.map.entries.slice();
400 for (slice.items(.key), 0..) |decl_cty, decl_i| {
401 const Context = struct {
402 arena: Allocator,
403 ctypes_map: []codegen.CType.Index,
404 cached_hash: codegen.CType.Store.Set.Map.Hash,
405 idx: codegen.CType.Index,
406
407 pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {
408 return ctx.cached_hash;
409 }
410 pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {
411 return lhs.eqlContext(rhs, ctx);
412 }
413 pub fn eqlIndex(
414 ctx: @This(),
415 lhs_idx: codegen.CType.Index,
416 rhs_idx: codegen.CType.Index,
417 ) bool {
418 if (lhs_idx < codegen.CType.Tag.no_payload_count or
419 rhs_idx < codegen.CType.Tag.no_payload_count) return lhs_idx == rhs_idx;
420 const lhs_i = lhs_idx - codegen.CType.Tag.no_payload_count;
421 if (lhs_i >= ctx.ctypes_map.len) return false;
422 return ctx.ctypes_map[lhs_i] == rhs_idx;
423 }
424 pub fn copyIndex(ctx: @This(), idx: codegen.CType.Index) codegen.CType.Index {
425 if (idx < codegen.CType.Tag.no_payload_count) return idx;
426 return ctx.ctypes_map[idx - codegen.CType.Tag.no_payload_count];
427 }
428 };
429 const decl_idx = @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + decl_i);
430 const ctx = Context{
431 .arena = global_ctypes.arena.allocator(),
432 .ctypes_map = f.ctypes_map.items,
433 .cached_hash = decl_ctypes.indexToHash(decl_idx),
434 .idx = decl_idx,
435 };
436 const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{
437 .store = &global_ctypes.set,
438 });
439 const global_idx =
440 @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + gop.index);
441 f.ctypes_map.appendAssumeCapacity(global_idx);
442 if (!gop.found_existing) {
443 errdefer _ = global_ctypes.set.map.pop();
444 gop.key_ptr.* = try decl_cty.copyContext(ctx);
445 }
446 if (std.debug.runtime_safety) {
447 const global_cty = &global_ctypes.set.map.entries.items(.key)[gop.index];
448 assert(global_cty == gop.key_ptr);
449 assert(decl_cty.eqlContext(global_cty.*, ctx));
450 assert(decl_cty.hash(decl_ctypes.set) == global_cty.hash(global_ctypes.set));
451 }
452 try codegen.genTypeDecl(
453 mod,
454 writer,
455 global_ctypes.set,
456 global_idx,
457 decl_index,
458 decl_ctypes.set,
459 decl_idx,
460 gop.found_existing,
461 );
462 }
360463}
361464
362fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
465fn flushErrDecls(self: *C, db: *DeclBlock) FlushDeclError!void {
363466 const gpa = self.base.allocator;
364467
365 const fwd_decl = &f.err_decls.fwd_decl;
366 const ctypes = &f.err_decls.ctypes;
367 const code = &f.err_decls.code;
468 const fwd_decl = &db.fwd_decl;
469 const ctypes = &db.ctypes;
470 const code = &db.code;
368471
369472 var object = codegen.Object{
370473 .dg = .{
371474 .gpa = gpa,
372475 .module = self.base.options.module.?,
373476 .error_msg = null,
374 .decl_index = undefined,
375 .decl = undefined,
477 .decl_index = .none,
478 .decl = null,
376479 .fwd_decl = fwd_decl.toManaged(gpa),
377480 .ctypes = ctypes.*,
378481 },
......@@ -394,19 +497,9 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
394497 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
395498 ctypes.* = object.dg.ctypes.move();
396499 code.* = object.code.moveToUnmanaged();
397
398 try self.flushCTypes(f, ctypes.*);
399 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
400 f.appendBufAssumeCapacity(fwd_decl.items);
401 f.appendBufAssumeCapacity(code.items);
402500}
403501
404fn flushLazyFn(
405 self: *C,
406 f: *Flush,
407 db: *DeclBlock,
408 lazy_fn: codegen.LazyFnMap.Entry,
409) FlushDeclError!void {
502fn flushLazyFn(self: *C, db: *DeclBlock, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void {
410503 const gpa = self.base.allocator;
411504
412505 const fwd_decl = &db.fwd_decl;
......@@ -418,8 +511,8 @@ fn flushLazyFn(
418511 .gpa = gpa,
419512 .module = self.base.options.module.?,
420513 .error_msg = null,
421 .decl_index = undefined,
422 .decl = undefined,
514 .decl_index = .none,
515 .decl = null,
423516 .fwd_decl = fwd_decl.toManaged(gpa),
424517 .ctypes = ctypes.*,
425518 },
......@@ -441,11 +534,6 @@ fn flushLazyFn(
441534 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
442535 ctypes.* = object.dg.ctypes.move();
443536 code.* = object.code.moveToUnmanaged();
444
445 try self.flushCTypes(f, ctypes.*);
446 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
447 f.appendBufAssumeCapacity(fwd_decl.items);
448 f.appendBufAssumeCapacity(code.items);
449537}
450538
451539fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
......@@ -456,8 +544,8 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError
456544 while (it.next()) |entry| {
457545 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
458546 if (gop.found_existing) continue;
459 gop.value_ptr.* = .{};
460 try self.flushLazyFn(f, gop.value_ptr, entry);
547 gop.value_ptr.* = {};
548 try self.flushLazyFn(&f.lazy_db, entry);
461549 }
462550}
463551
......@@ -481,7 +569,6 @@ fn flushDecl(
481569
482570 const decl_block = self.decl_table.getPtr(decl_index).?;
483571
484 try self.flushCTypes(f, decl_block.ctypes);
485572 try self.flushLazyFns(f, decl_block.lazy_fns);
486573 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
487574 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))