authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-18 23:03:11-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-21 00:00:19-05:00
logcf7200e8f9c995bae8bedaf3c727fe710a93f1e9
treec7a55cfb158bfb0cd4f74142a0eff0c756c727b5
parent3eed197c95c21d850d503687f445946e6bd429c5

CBE: remove typedef data structures

Adds a new mechanism for `@tagName` function generation that doesn't piggyback on the removed typedef system.

4 files changed, 241 insertions(+), 705 deletions(-)

src/Compilation.zig+1-6
......@@ -3277,14 +3277,9 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
32773277 .decl = decl,
32783278 .fwd_decl = fwd_decl.toManaged(gpa),
32793279 .ctypes = .{},
3280 .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }),
3281 .typedefs_arena = ctypes_arena.allocator(),
32823280 };
32833281 defer {
3284 for (dg.typedefs.values()) |typedef| {
3285 module.gpa.free(typedef.rendered);
3286 }
3287 dg.typedefs.deinit();
3282 dg.ctypes.deinit(gpa);
32883283 dg.fwd_decl.deinit();
32893284 }
32903285
src/codegen/c.zig+88-555
......@@ -23,7 +23,7 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
2323const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
2424const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { Const, ConstArgument, Mut };
26const Mutability = enum { @"const", mut };
2727const BigIntLimb = std.math.big.Limb;
2828const BigInt = std.math.big.int;
2929
......@@ -63,12 +63,17 @@ const TypedefKind = enum {
6363};
6464
6565pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
66pub const TypedefMap = std.ArrayHashMap(
67 Type,
68 struct { name: []const u8, rendered: []u8 },
69 Type.HashContext32,
70 true,
71);
66
67pub const LazyFnKey = union(enum) {
68 tag_name: Decl.Index,
69};
70pub const LazyFnValue = struct {
71 fn_name: []const u8,
72 data: union {
73 tag_name: Type,
74 },
75};
76pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
7277
7378const LoopDepth = u16;
7479const Local = struct {
......@@ -83,11 +88,6 @@ const LocalsList = std.ArrayListUnmanaged(LocalIndex);
8388const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);
8489const LocalsStack = std.ArrayListUnmanaged(LocalsMap);
8590
86const FormatTypeAsCIdentContext = struct {
87 ty: Type,
88 mod: *Module,
89};
90
9191const ValueRenderLocation = enum {
9292 FunctionArgument,
9393 Initializer,
......@@ -108,26 +108,6 @@ const BuiltinInfo = enum {
108108 Bits,
109109};
110110
111fn formatTypeAsCIdentifier(
112 data: FormatTypeAsCIdentContext,
113 comptime fmt: []const u8,
114 options: std.fmt.FormatOptions,
115 writer: anytype,
116) !void {
117 var stack = std.heap.stackFallback(128, data.mod.gpa);
118 const allocator = stack.get();
119 const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch "";
120 defer allocator.free(str);
121 return formatIdent(str, fmt, options, writer);
122}
123
124pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) {
125 return .{ .data = .{
126 .ty = ty,
127 .mod = mod,
128 } };
129}
130
131111const reserved_idents = std.ComptimeStringMap(void, .{
132112 // C language
133113 .{ "alignas", {
......@@ -283,6 +263,7 @@ pub const Function = struct {
283263 next_arg_index: usize = 0,
284264 next_block_index: usize = 0,
285265 object: Object,
266 lazy_fns: LazyFnMap,
286267 func: *Module.Fn,
287268 /// All the locals, to be emitted at the top of the function.
288269 locals: std.ArrayListUnmanaged(Local) = .{},
......@@ -319,7 +300,7 @@ pub const Function = struct {
319300 const gpa = f.object.dg.gpa;
320301 try f.allocs.put(gpa, decl_c_value.local, true);
321302 try writer.writeAll("static ");
322 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
303 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);
323304 try writer.writeAll(" = ");
324305 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
325306 try writer.writeAll(";\n ");
......@@ -353,7 +334,7 @@ pub const Function = struct {
353334 }
354335
355336 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
356 const result = try f.allocAlignedLocal(ty, .Mut, 0);
337 const result = try f.allocAlignedLocal(ty, .mut, 0);
357338 log.debug("%{d}: allocating t{d}", .{ inst, result.local });
358339 return result;
359340 }
......@@ -448,6 +429,29 @@ pub const Function = struct {
448429 return f.object.dg.fmtIntLiteral(ty, val);
449430 }
450431
432 fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 {
433 const gpa = f.object.dg.gpa;
434 const owner_decl = enum_ty.getOwnerDecl();
435
436 const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl });
437 if (!gop.found_existing) {
438 errdefer _ = f.lazy_fns.pop();
439
440 var promoted = f.object.dg.ctypes.promote(gpa);
441 defer f.object.dg.ctypes.demote(promoted);
442 const arena = promoted.arena.allocator();
443
444 gop.value_ptr.* = .{
445 .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{
446 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
447 @enumToInt(owner_decl),
448 }),
449 .data = .{ .tag_name = try enum_ty.copy(arena) },
450 };
451 }
452 return gop.value_ptr.fn_name;
453 }
454
451455 pub fn deinit(f: *Function) void {
452456 const gpa = f.object.dg.gpa;
453457 f.allocs.deinit(gpa);
......@@ -458,11 +462,8 @@ pub const Function = struct {
458462 f.free_locals_stack.deinit(gpa);
459463 f.blocks.deinit(gpa);
460464 f.value_map.deinit();
465 f.lazy_fns.deinit(gpa);
461466 f.object.code.deinit();
462 for (f.object.dg.typedefs.values()) |typedef| {
463 gpa.free(typedef.rendered);
464 }
465 f.object.dg.typedefs.deinit();
466467 f.object.dg.ctypes.deinit(gpa);
467468 f.object.dg.fwd_decl.deinit();
468469 f.arena.deinit();
......@@ -492,9 +493,6 @@ pub const DeclGen = struct {
492493 fwd_decl: std.ArrayList(u8),
493494 error_msg: ?*Module.ErrorMsg,
494495 ctypes: CType.Store,
495 /// The key of this map is Type which has references to typedefs_arena.
496 typedefs: TypedefMap,
497 typedefs_arena: std.mem.Allocator,
498496
499497 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
500498 @setCold(true);
......@@ -504,14 +502,6 @@ pub const DeclGen = struct {
504502 return error.AnalysisFail;
505503 }
506504
507 fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 {
508 if (dg.typedefs.get(t)) |typedef| {
509 return typedef.name;
510 } else {
511 return null;
512 }
513 }
514
515505 fn renderDeclValue(
516506 dg: *DeclGen,
517507 writer: anytype,
......@@ -1493,7 +1483,7 @@ pub const DeclGen = struct {
14931483 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
14941484 if (index > 0) try w.writeAll(", ");
14951485 const name = CValue{ .arg = index };
1496 try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind);
1486 try dg.renderTypeAndName(w, param_type, name, .@"const", 0, kind);
14971487 index += 1;
14981488 }
14991489
......@@ -1507,453 +1497,6 @@ pub const DeclGen = struct {
15071497 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
15081498 }
15091499
1510 fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1511 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1512 defer buffer.deinit();
1513 const bw = buffer.writer();
1514
1515 const fn_info = t.fnInfo();
1516
1517 const target = dg.module.getTarget();
1518 var ret_buf: LowerFnRetTyBuffer = undefined;
1519 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1520
1521 try bw.writeAll("typedef ");
1522 try dg.renderType(bw, ret_ty, .Forward);
1523 try bw.writeAll(" (*");
1524 const name_begin = buffer.items.len;
1525 try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});
1526 const name_end = buffer.items.len;
1527 try bw.writeAll(")(");
1528
1529 const param_len = fn_info.param_types.len;
1530
1531 var params_written: usize = 0;
1532 var index: usize = 0;
1533 while (index < param_len) : (index += 1) {
1534 const param_ty = fn_info.param_types[index];
1535 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
1536 if (params_written > 0) {
1537 try bw.writeAll(", ");
1538 }
1539 try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward);
1540 params_written += 1;
1541 }
1542
1543 if (fn_info.is_var_args) {
1544 if (params_written != 0) try bw.writeAll(", ");
1545 try bw.writeAll("...");
1546 } else if (params_written == 0) {
1547 try dg.renderType(bw, Type.void, .Forward);
1548 }
1549 try bw.writeAll(");\n");
1550
1551 const rendered = try buffer.toOwnedSlice();
1552 errdefer dg.typedefs.allocator.free(rendered);
1553 const name = rendered[name_begin..name_end];
1554
1555 try dg.typedefs.ensureUnusedCapacity(1);
1556 dg.typedefs.putAssumeCapacityNoClobber(
1557 try t.copy(dg.typedefs_arena),
1558 .{ .name = name, .rendered = rendered },
1559 );
1560
1561 return name;
1562 }
1563
1564 fn renderSliceTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1565 std.debug.assert(t.sentinel() == null); // expected canonical type
1566
1567 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1568 defer buffer.deinit();
1569 const bw = buffer.writer();
1570
1571 var ptr_ty_buf: Type.SlicePtrFieldTypeBuffer = undefined;
1572 const ptr_ty = t.slicePtrFieldType(&ptr_ty_buf);
1573 const ptr_name = CValue{ .identifier = "ptr" };
1574 const len_ty = Type.usize;
1575 const len_name = CValue{ .identifier = "len" };
1576
1577 try bw.writeAll("typedef struct {\n ");
1578 try dg.renderTypeAndName(bw, ptr_ty, ptr_name, .Mut, 0, .Complete);
1579 try bw.writeAll(";\n ");
1580 try dg.renderTypeAndName(bw, len_ty, len_name, .Mut, 0, .Complete);
1581
1582 try bw.writeAll(";\n} ");
1583 const name_begin = buffer.items.len;
1584 try bw.print("zig_{c}_{}", .{
1585 @as(u8, if (t.isConstPtr()) 'L' else 'M'),
1586 typeToCIdentifier(t.childType(), dg.module),
1587 });
1588 const name_end = buffer.items.len;
1589 try bw.writeAll(";\n");
1590
1591 const rendered = try buffer.toOwnedSlice();
1592 errdefer dg.typedefs.allocator.free(rendered);
1593 const name = rendered[name_begin..name_end];
1594
1595 try dg.typedefs.ensureUnusedCapacity(1);
1596 dg.typedefs.putAssumeCapacityNoClobber(
1597 try t.copy(dg.typedefs_arena),
1598 .{ .name = name, .rendered = rendered },
1599 );
1600
1601 return name;
1602 }
1603
1604 fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1605 // The forward declaration for T is stored with a key of *const T.
1606 const child_ty = t.childType();
1607
1608 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1609 defer buffer.deinit();
1610 const bw = buffer.writer();
1611
1612 const tag = switch (child_ty.zigTypeTag()) {
1613 .Struct, .ErrorUnion, .Optional => "struct",
1614 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct" else "union",
1615 else => unreachable,
1616 };
1617 try bw.writeAll("typedef ");
1618 try bw.writeAll(tag);
1619 const name_begin = buffer.items.len + " ".len;
1620 try bw.writeAll(" zig_");
1621 switch (child_ty.zigTypeTag()) {
1622 .Struct, .Union => {
1623 var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
1624 defer fqn_buf.deinit();
1625
1626 const owner_decl_index = child_ty.getOwnerDecl();
1627 const owner_decl = dg.module.declPtr(owner_decl_index);
1628 try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
1629
1630 try bw.print("S_{}__{d}", .{ fmtIdent(fqn_buf.items), @enumToInt(owner_decl_index) });
1631 },
1632 .ErrorUnion => {
1633 try bw.print("E_{}", .{typeToCIdentifier(child_ty.errorUnionPayload(), dg.module)});
1634 },
1635 .Optional => {
1636 var opt_buf: Type.Payload.ElemType = undefined;
1637 try bw.print("Q_{}", .{typeToCIdentifier(child_ty.optionalChild(&opt_buf), dg.module)});
1638 },
1639 else => unreachable,
1640 }
1641 const name_end = buffer.items.len;
1642 try buffer.ensureUnusedCapacity(" ".len + (name_end - name_begin) + ";\n".len);
1643 buffer.appendAssumeCapacity(' ');
1644 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
1645 buffer.appendSliceAssumeCapacity(";\n");
1646
1647 const rendered = try buffer.toOwnedSlice();
1648 errdefer dg.typedefs.allocator.free(rendered);
1649 const name = rendered[name_begin..name_end];
1650
1651 try dg.typedefs.ensureUnusedCapacity(1);
1652 dg.typedefs.putAssumeCapacityNoClobber(
1653 try t.copy(dg.typedefs_arena),
1654 .{ .name = name, .rendered = rendered },
1655 );
1656
1657 return name;
1658 }
1659
1660 fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1661 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1662 const ptr_ty = Type.initPayload(&ptr_pl.base);
1663 const name = dg.getTypedefName(ptr_ty) orelse
1664 try dg.renderFwdTypedef(ptr_ty);
1665
1666 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1667 defer buffer.deinit();
1668
1669 try buffer.appendSlice("struct ");
1670
1671 var needs_pack_attr = false;
1672 {
1673 var it = t.structFields().iterator();
1674 while (it.next()) |field| {
1675 const field_ty = field.value_ptr.ty;
1676 if (!field_ty.hasRuntimeBits()) continue;
1677 const alignment = field.value_ptr.abi_align;
1678 if (alignment != 0 and alignment < field_ty.abiAlignment(dg.module.getTarget())) {
1679 needs_pack_attr = true;
1680 try buffer.appendSlice("zig_packed(");
1681 break;
1682 }
1683 }
1684 }
1685
1686 try buffer.appendSlice(name);
1687 try buffer.appendSlice(" {\n");
1688 {
1689 var it = t.structFields().iterator();
1690 var empty = true;
1691 while (it.next()) |field| {
1692 const field_ty = field.value_ptr.ty;
1693 if (!field_ty.hasRuntimeBits()) continue;
1694
1695 const alignment = field.value_ptr.alignment(dg.module.getTarget(), t.containerLayout());
1696 const field_name = CValue{ .identifier = field.key_ptr.* };
1697 try buffer.append(' ');
1698 try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
1699 try buffer.appendSlice(";\n");
1700
1701 empty = false;
1702 }
1703 if (empty) try buffer.appendSlice(" char empty_struct;\n");
1704 }
1705 if (needs_pack_attr) try buffer.appendSlice("});\n") else try buffer.appendSlice("};\n");
1706
1707 const rendered = try buffer.toOwnedSlice();
1708 errdefer dg.typedefs.allocator.free(rendered);
1709
1710 try dg.typedefs.ensureUnusedCapacity(1);
1711 dg.typedefs.putAssumeCapacityNoClobber(
1712 try t.copy(dg.typedefs_arena),
1713 .{ .name = name, .rendered = rendered },
1714 );
1715
1716 return name;
1717 }
1718
1719 fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1720 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1721 defer buffer.deinit();
1722
1723 try buffer.appendSlice("typedef struct {\n");
1724 {
1725 const fields = t.tupleFields();
1726 var field_id: usize = 0;
1727 for (fields.types, 0..) |field_ty, i| {
1728 if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
1729
1730 try buffer.append(' ');
1731 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete);
1732 try buffer.appendSlice(";\n");
1733
1734 field_id += 1;
1735 }
1736 if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n");
1737 }
1738 const name_begin = buffer.items.len + "} ".len;
1739 try buffer.writer().print("}} zig_T_{}_{d};\n", .{ typeToCIdentifier(t, dg.module), @truncate(u16, t.hash(dg.module)) });
1740 const name_end = buffer.items.len - ";\n".len;
1741
1742 const rendered = try buffer.toOwnedSlice();
1743 errdefer dg.typedefs.allocator.free(rendered);
1744 const name = rendered[name_begin..name_end];
1745
1746 try dg.typedefs.ensureUnusedCapacity(1);
1747 dg.typedefs.putAssumeCapacityNoClobber(
1748 try t.copy(dg.typedefs_arena),
1749 .{ .name = name, .rendered = rendered },
1750 );
1751
1752 return name;
1753 }
1754
1755 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1756 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1757 const ptr_ty = Type.initPayload(&ptr_pl.base);
1758 const name = dg.getTypedefName(ptr_ty) orelse
1759 try dg.renderFwdTypedef(ptr_ty);
1760
1761 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1762 defer buffer.deinit();
1763
1764 try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union ");
1765 try buffer.appendSlice(name);
1766 try buffer.appendSlice(" {\n");
1767
1768 const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: {
1769 const target = dg.module.getTarget();
1770 const layout = t.unionGetLayout(target);
1771 if (layout.tag_size != 0) {
1772 try buffer.append(' ');
1773 try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete);
1774 try buffer.appendSlice(";\n");
1775 }
1776 try buffer.appendSlice(" union {\n");
1777 break :indent " ";
1778 } else " ";
1779
1780 {
1781 var it = t.unionFields().iterator();
1782 var empty = true;
1783 while (it.next()) |field| {
1784 const field_ty = field.value_ptr.ty;
1785 if (!field_ty.hasRuntimeBits()) continue;
1786
1787 const alignment = field.value_ptr.abi_align;
1788 const field_name = CValue{ .identifier = field.key_ptr.* };
1789 try buffer.appendSlice(indent);
1790 try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
1791 try buffer.appendSlice(";\n");
1792
1793 empty = false;
1794 }
1795 if (empty) {
1796 try buffer.appendSlice(indent);
1797 try buffer.appendSlice("char empty_union;\n");
1798 }
1799 }
1800
1801 if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n");
1802 try buffer.appendSlice("};\n");
1803
1804 const rendered = try buffer.toOwnedSlice();
1805 errdefer dg.typedefs.allocator.free(rendered);
1806
1807 try dg.typedefs.ensureUnusedCapacity(1);
1808 dg.typedefs.putAssumeCapacityNoClobber(
1809 try t.copy(dg.typedefs_arena),
1810 .{ .name = name, .rendered = rendered },
1811 );
1812
1813 return name;
1814 }
1815
1816 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1817 assert(t.errorUnionSet().tag() == .anyerror);
1818
1819 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1820 const ptr_ty = Type.initPayload(&ptr_pl.base);
1821 const name = dg.getTypedefName(ptr_ty) orelse
1822 try dg.renderFwdTypedef(ptr_ty);
1823
1824 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1825 defer buffer.deinit();
1826 const bw = buffer.writer();
1827
1828 const payload_ty = t.errorUnionPayload();
1829 const payload_name = CValue{ .identifier = "payload" };
1830 const error_ty = t.errorUnionSet();
1831 const error_name = CValue{ .identifier = "error" };
1832
1833 const target = dg.module.getTarget();
1834 const payload_align = payload_ty.abiAlignment(target);
1835 const error_align = error_ty.abiAlignment(target);
1836 try bw.writeAll("struct ");
1837 try bw.writeAll(name);
1838 try bw.writeAll(" {\n ");
1839 if (error_align > payload_align) {
1840 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1841 try bw.writeAll(";\n ");
1842 try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
1843 } else {
1844 try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
1845 try bw.writeAll(";\n ");
1846 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1847 }
1848 try bw.writeAll(";\n};\n");
1849
1850 const rendered = try buffer.toOwnedSlice();
1851 errdefer dg.typedefs.allocator.free(rendered);
1852
1853 try dg.typedefs.ensureUnusedCapacity(1);
1854 dg.typedefs.putAssumeCapacityNoClobber(
1855 try t.copy(dg.typedefs_arena),
1856 .{ .name = name, .rendered = rendered },
1857 );
1858
1859 return name;
1860 }
1861
1862 fn renderArrayTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1863 const info = t.arrayInfo();
1864 std.debug.assert(info.sentinel == null); // expected canonical type
1865
1866 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1867 defer buffer.deinit();
1868 const bw = buffer.writer();
1869
1870 try bw.writeAll("typedef ");
1871 try dg.renderType(bw, info.elem_type, .Complete);
1872
1873 const name_begin = buffer.items.len + " ".len;
1874 try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
1875 const name_end = buffer.items.len;
1876
1877 const c_len = if (info.len > 0) info.len else 1;
1878 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
1879 const c_len_val = Value.initPayload(&c_len_pl.base);
1880 try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
1881
1882 const rendered = try buffer.toOwnedSlice();
1883 errdefer dg.typedefs.allocator.free(rendered);
1884 const name = rendered[name_begin..name_end];
1885
1886 try dg.typedefs.ensureUnusedCapacity(1);
1887 dg.typedefs.putAssumeCapacityNoClobber(
1888 try t.copy(dg.typedefs_arena),
1889 .{ .name = name, .rendered = rendered },
1890 );
1891
1892 return name;
1893 }
1894
1895 fn renderOptionalTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1896 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1897 const ptr_ty = Type.initPayload(&ptr_pl.base);
1898 const name = dg.getTypedefName(ptr_ty) orelse
1899 try dg.renderFwdTypedef(ptr_ty);
1900
1901 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1902 defer buffer.deinit();
1903 const bw = buffer.writer();
1904
1905 var opt_buf: Type.Payload.ElemType = undefined;
1906 const child_ty = t.optionalChild(&opt_buf);
1907
1908 try bw.writeAll("struct ");
1909 try bw.writeAll(name);
1910 try bw.writeAll(" {\n");
1911 try dg.renderTypeAndName(bw, child_ty, .{ .identifier = "payload" }, .Mut, 0, .Complete);
1912 try bw.writeAll(";\n ");
1913 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1914 try bw.writeAll(";\n};\n");
1915
1916 const rendered = try buffer.toOwnedSlice();
1917 errdefer dg.typedefs.allocator.free(rendered);
1918
1919 try dg.typedefs.ensureUnusedCapacity(1);
1920 dg.typedefs.putAssumeCapacityNoClobber(
1921 try t.copy(dg.typedefs_arena),
1922 .{ .name = name, .rendered = rendered },
1923 );
1924
1925 return name;
1926 }
1927
1928 fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1929 const opaque_ty = t.cast(Type.Payload.Opaque).?.data;
1930 const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name;
1931 const fqn = try opaque_ty.getFullyQualifiedName(dg.module);
1932 defer dg.typedefs.allocator.free(fqn);
1933
1934 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1935 defer buffer.deinit();
1936
1937 try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))});
1938
1939 const name_begin = buffer.items.len;
1940 try buffer.writer().print("zig_O_{}", .{fmtIdent(fqn)});
1941 const name_end = buffer.items.len;
1942 try buffer.appendSlice(";\n");
1943
1944 const rendered = try buffer.toOwnedSlice();
1945 errdefer dg.typedefs.allocator.free(rendered);
1946 const name = rendered[name_begin..name_end];
1947
1948 try dg.typedefs.ensureUnusedCapacity(1);
1949 dg.typedefs.putAssumeCapacityNoClobber(
1950 try t.copy(dg.typedefs_arena),
1951 .{ .name = name, .rendered = rendered },
1952 );
1953
1954 return name;
1955 }
1956
19571500 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
19581501 return dg.ctypes.indexToCType(idx);
19591502 }
......@@ -2408,31 +1951,27 @@ pub const DeclGen = struct {
24081951 const idx = try dg.typeToIndex(ty);
24091952 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{
24101953 .@"const" = switch (mutability) {
2411 .Const, .ConstArgument => true,
2412 .Mut => false,
1954 .mut => false,
1955 .@"const" => true,
24131956 },
24141957 }))});
24151958 try dg.writeCValue(w, name);
24161959 try dg.renderTypeSuffix(w, idx, .suffix);
24171960 }
24181961
2419 fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
2420 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
2421 defer buffer.deinit();
2422 const bw = buffer.writer();
2423
1962 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
24241963 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
24251964
2426 try buffer.appendSlice("static ");
2427 try dg.renderType(bw, name_slice_ty, .Complete);
2428 const name_begin = buffer.items.len + " ".len;
2429 try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) });
2430 const name_end = buffer.items.len - "(".len;
2431 try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);
2432 try buffer.appendSlice(") {\n switch (tag) {\n");
1965 try w.writeAll("static ");
1966 try dg.renderType(w, name_slice_ty, .Complete);
1967 try w.writeByte(' ');
1968 try w.writeAll(fn_name);
1969 try w.writeByte('(');
1970 try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete);
1971 try w.writeAll(") {\n switch (tag) {\n");
24331972 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2434 const name_z = try dg.typedefs.allocator.dupeZ(u8, name);
2435 defer dg.typedefs.allocator.free(name_z);
1973 const name_z = try dg.gpa.dupeZ(u8, name);
1974 defer dg.gpa.free(name_z);
24361975 const name_bytes = name_z[0 .. name_z.len + 1];
24371976
24381977 var tag_pl: Value.Payload.U32 = .{
......@@ -2453,40 +1992,23 @@ pub const DeclGen = struct {
24531992 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
24541993 const len_val = Value.initPayload(&len_pl.base);
24551994
2456 try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
2457 try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete);
2458 try buffer.appendSlice(" = ");
2459 try dg.renderValue(bw, name_ty, name_val, .Initializer);
2460 try buffer.appendSlice(";\n return (");
2461 try dg.renderTypecast(bw, name_slice_ty);
2462 try bw.print("){{{}, {}}};\n", .{
1995 try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
1996 try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete);
1997 try w.writeAll(" = ");
1998 try dg.renderValue(w, name_ty, name_val, .Initializer);
1999 try w.writeAll(";\n return (");
2000 try dg.renderTypecast(w, name_slice_ty);
2001 try w.print("){{{}, {}}};\n", .{
24632002 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
24642003 });
24652004
2466 try buffer.appendSlice(" }\n");
2005 try w.writeAll(" }\n");
24672006 }
2468 try buffer.appendSlice(" }\n while (");
2469 try dg.renderValue(bw, Type.bool, Value.true, .Other);
2470 try buffer.appendSlice(") ");
2471 _ = try airBreakpoint(bw);
2472 try buffer.appendSlice("}\n");
2473
2474 const rendered = try buffer.toOwnedSlice();
2475 errdefer dg.typedefs.allocator.free(rendered);
2476 const name = rendered[name_begin..name_end];
2477
2478 try dg.typedefs.ensureUnusedCapacity(1);
2479 dg.typedefs.putAssumeCapacityNoClobber(
2480 try enum_ty.copy(dg.typedefs_arena),
2481 .{ .name = name, .rendered = rendered },
2482 );
2483
2484 return name;
2485 }
2486
2487 fn getTagNameFn(dg: *DeclGen, enum_ty: Type) ![]const u8 {
2488 return dg.getTypedefName(enum_ty) orelse
2489 try dg.renderTagNameFn(enum_ty);
2007 try w.writeAll(" }\n while (");
2008 try dg.renderValue(w, Type.bool, Value.true, .Other);
2009 try w.writeAll(") ");
2010 _ = try airBreakpoint(w);
2011 try w.writeAll("}\n");
24902012 }
24912013
24922014 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
......@@ -2724,7 +2246,7 @@ pub fn genErrDecls(o: *Object) !void {
27242246 const name_val = Value.initPayload(&name_pl.base);
27252247
27262248 try writer.writeAll("static ");
2727 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
2249 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .@"const", 0, .Complete);
27282250 try writer.writeAll(" = ");
27292251 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
27302252 try writer.writeAll(";\n");
......@@ -2737,7 +2259,7 @@ pub fn genErrDecls(o: *Object) !void {
27372259 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
27382260
27392261 try writer.writeAll("static ");
2740 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete);
2262 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .@"const", 0, .Complete);
27412263 try writer.writeAll(" = {");
27422264 for (o.dg.module.error_name_list.items, 0..) |name, value| {
27432265 if (value != 0) try writer.writeByte(',');
......@@ -2767,6 +2289,17 @@ fn genExports(o: *Object) !void {
27672289 };
27682290}
27692291
2292pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2293 const writer = o.writer();
2294 switch (lazy_fn.key_ptr.*) {
2295 .tag_name => _ = try o.dg.renderTagNameFn(
2296 writer,
2297 lazy_fn.value_ptr.fn_name,
2298 lazy_fn.value_ptr.data.tag_name,
2299 ),
2300 }
2301}
2302
27702303pub fn genFunc(f: *Function) !void {
27712304 const tracy = trace(@src());
27722305 defer tracy.end();
......@@ -2845,7 +2378,7 @@ pub fn genFunc(f: *Function) !void {
28452378 w,
28462379 local.ty,
28472380 .{ .local = local_index },
2848 .Mut,
2381 .mut,
28492382 local.alignment,
28502383 .Complete,
28512384 );
......@@ -2886,7 +2419,7 @@ pub fn genDecl(o: *Object) !void {
28862419
28872420 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
28882421 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2889 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
2422 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
28902423 try fwd_decl_writer.writeAll(";\n");
28912424 try genExports(o);
28922425
......@@ -2896,7 +2429,7 @@ pub fn genDecl(o: *Object) !void {
28962429 if (!is_global) try w.writeAll("static ");
28972430 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
28982431 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2899 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
2432 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);
29002433 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");
29012434 try w.writeAll(" = ");
29022435 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
......@@ -2908,13 +2441,13 @@ pub fn genDecl(o: *Object) !void {
29082441 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
29092442
29102443 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2911 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);
2444 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
29122445 try fwd_decl_writer.writeAll(";\n");
29132446
29142447 const w = o.writer();
29152448 if (!is_global) try w.writeAll("static ");
29162449 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2917 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);
2450 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);
29182451 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");
29192452 try w.writeAll(" = ");
29202453 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
......@@ -3443,7 +2976,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
34432976 return CValue{ .undef = inst_ty };
34442977 }
34452978
3446 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2979 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
34472980 const target = f.object.dg.module.getTarget();
34482981 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
34492982 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
......@@ -3460,7 +2993,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34602993 return CValue{ .undef = inst_ty };
34612994 }
34622995
3463 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2996 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
34642997 const target = f.object.dg.module.getTarget();
34652998 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
34662999 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
......@@ -4937,7 +4470,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
49374470 writer,
49384471 output_ty,
49394472 local_value,
4940 .Mut,
4473 .mut,
49414474 alignment,
49424475 .Complete,
49434476 );
......@@ -4976,7 +4509,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
49764509 writer,
49774510 input_ty,
49784511 local_value,
4979 .Const,
4512 .@"const",
49804513 alignment,
49814514 .Complete,
49824515 );
......@@ -6474,7 +6007,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
64746007 const writer = f.object.writer();
64756008 const local = try f.allocLocal(inst, inst_ty);
64766009 try f.writeCValue(writer, local, .Other);
6477 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
6010 try writer.print(" = {s}(", .{try f.getTagNameFn(enum_ty)});
64786011 try f.writeCValue(writer, operand, .Other);
64796012 try writer.writeAll(");\n");
64806013
src/codegen/c/type.zig+11-11
......@@ -290,11 +290,11 @@ pub const CType = extern union {
290290 }
291291 };
292292
293 const Promoted = struct {
293 pub const Promoted = struct {
294294 arena: std.heap.ArenaAllocator,
295295 set: Set,
296296
297 fn gpa(self: *Promoted) Allocator {
297 pub fn gpa(self: *Promoted) Allocator {
298298 return self.arena.child_allocator;
299299 }
300300
......@@ -345,11 +345,11 @@ pub const CType = extern union {
345345 }
346346 };
347347
348 fn promote(self: Store, gpa: Allocator) Promoted {
348 pub fn promote(self: Store, gpa: Allocator) Promoted {
349349 return .{ .arena = self.arena.promote(gpa), .set = self.set };
350350 }
351351
352 fn demote(self: *Store, promoted: Promoted) void {
352 pub fn demote(self: *Store, promoted: Promoted) void {
353353 self.arena = promoted.arena.state;
354354 self.set = promoted.set;
355355 }
......@@ -382,17 +382,17 @@ pub const CType = extern union {
382382 _ = promoted.arena.reset(.retain_capacity);
383383 }
384384
385 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
386 self.map.shrinkAndFree(gpa, self.map.entries.len);
387 }
388
389 pub fn shrinkAndFree(self: *Store, gpa: Allocator) void {
385 pub fn clearAndFree(self: *Store, gpa: Allocator) void {
390386 var promoted = self.promote(gpa);
391387 defer self.demote(promoted);
392388 promoted.set.map.clearAndFree(gpa);
393389 _ = promoted.arena.reset(.free_all);
394390 }
395391
392 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
393 self.set.map.shrinkAndFree(gpa, self.set.map.count());
394 }
395
396396 pub fn move(self: *Store) Store {
397397 const moved = self.*;
398398 self.* = .{};
......@@ -1252,8 +1252,8 @@ pub const CType = extern union {
12521252 pub const HashContext64 = struct {
12531253 store: *const Store.Set,
12541254
1255 pub fn hash(_: @This(), cty: CType) u64 {
1256 return cty.hash();
1255 pub fn hash(self: @This(), cty: CType) u64 {
1256 return cty.hash(self.store.*);
12571257 }
12581258 pub fn eql(_: @This(), lhs: CType, rhs: CType) bool {
12591259 return lhs.eql(rhs);
src/link/C.zig+141-133
......@@ -22,26 +22,19 @@ base: link.File,
2222/// Instead, it tracks all declarations in this table, and iterates over it
2323/// in the flush function, stitching pre-rendered pieces of C code together.
2424decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},
25/// Stores Type/Value data for `typedefs` to reference.
26/// Accumulates allocations and then there is a periodic garbage collection after flush().
27arena: std.heap.ArenaAllocator,
2825
2926/// Per-declaration data.
3027const DeclBlock = struct {
3128 code: std.ArrayListUnmanaged(u8) = .{},
3229 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
30 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
31 /// over each `Decl` and generate the definition for each used `CType` once.
3332 ctypes: codegen.CType.Store = .{},
34 /// Each Decl stores a mapping of Zig Types to corresponding C types, for every
35 /// Zig Type used by the Decl. In flush(), we iterate over each Decl
36 /// and emit the typedef code for all types, making sure to not emit the same thing twice.
37 /// Any arena memory the Type points to lives in the `arena` field of `C`.
38 typedefs: codegen.TypedefMap.Unmanaged = .{},
33 /// Key and Value storage use the ctype arena.
34 lazy_fns: codegen.LazyFnMap = .{},
3935
4036 fn deinit(db: *DeclBlock, gpa: Allocator) void {
41 for (db.typedefs.values()) |typedef| {
42 gpa.free(typedef.rendered);
43 }
44 db.typedefs.deinit(gpa);
37 db.lazy_fns.deinit(gpa);
4538 db.ctypes.deinit(gpa);
4639 db.fwd_decl.deinit(gpa);
4740 db.code.deinit(gpa);
......@@ -66,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
6659 errdefer gpa.destroy(c_file);
6760
6861 c_file.* = C{
69 .arena = std.heap.ArenaAllocator.init(gpa),
7062 .base = .{
7163 .tag = .c,
7264 .options = options,
......@@ -85,8 +77,6 @@ pub fn deinit(self: *C) void {
8577 db.deinit(gpa);
8678 }
8779 self.decl_table.deinit(gpa);
88
89 self.arena.deinit();
9080}
9181
9282pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
......@@ -101,44 +91,42 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
10191 const tracy = trace(@src());
10292 defer tracy.end();
10393
94 const gpa = self.base.allocator;
95
10496 const decl_index = func.owner_decl;
105 const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);
97 const gop = try self.decl_table.getOrPut(gpa, decl_index);
10698 if (!gop.found_existing) {
10799 gop.value_ptr.* = .{};
108100 }
109 const fwd_decl = &gop.value_ptr.fwd_decl;
110101 const ctypes = &gop.value_ptr.ctypes;
111 const typedefs = &gop.value_ptr.typedefs;
102 const lazy_fns = &gop.value_ptr.lazy_fns;
103 const fwd_decl = &gop.value_ptr.fwd_decl;
112104 const code = &gop.value_ptr.code;
105 ctypes.clearRetainingCapacity(gpa);
106 lazy_fns.clearRetainingCapacity();
113107 fwd_decl.shrinkRetainingCapacity(0);
114 ctypes.clearRetainingCapacity(module.gpa);
115 for (typedefs.values()) |typedef| {
116 module.gpa.free(typedef.rendered);
117 }
118 typedefs.clearRetainingCapacity();
119108 code.shrinkRetainingCapacity(0);
120109
121110 var function: codegen.Function = .{
122 .value_map = codegen.CValueMap.init(module.gpa),
111 .value_map = codegen.CValueMap.init(gpa),
123112 .air = air,
124113 .liveness = liveness,
125114 .func = func,
126115 .object = .{
127116 .dg = .{
128 .gpa = module.gpa,
117 .gpa = gpa,
129118 .module = module,
130119 .error_msg = null,
131120 .decl_index = decl_index,
132121 .decl = module.declPtr(decl_index),
133 .fwd_decl = fwd_decl.toManaged(module.gpa),
122 .fwd_decl = fwd_decl.toManaged(gpa),
134123 .ctypes = ctypes.*,
135 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
136 .typedefs_arena = self.arena.allocator(),
137124 },
138 .code = code.toManaged(module.gpa),
125 .code = code.toManaged(gpa),
139126 .indent_writer = undefined, // set later so we can get a pointer to object.code
140127 },
141 .arena = std.heap.ArenaAllocator.init(module.gpa),
128 .lazy_fns = lazy_fns.*,
129 .arena = std.heap.ArenaAllocator.init(gpa),
142130 };
143131
144132 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
......@@ -146,91 +134,79 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
146134
147135 codegen.genFunc(&function) catch |err| switch (err) {
148136 error.AnalysisFail => {
149 try module.failed_decls.put(module.gpa, decl_index, function.object.dg.error_msg.?);
137 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
150138 return;
151139 },
152140 else => |e| return e,
153141 };
154142
155 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
156143 ctypes.* = function.object.dg.ctypes.move();
157 typedefs.* = function.object.dg.typedefs.unmanaged;
158 function.object.dg.typedefs.unmanaged = .{};
144 lazy_fns.* = function.lazy_fns.move();
145 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
159146 code.* = function.object.code.moveToUnmanaged();
160147
161148 // Free excess allocated memory for this Decl.
162 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
163 code.shrinkAndFree(module.gpa, code.items.len);
164 ctypes.shrinkAndFree(module.gpa);
149 ctypes.shrinkToFit(gpa);
150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
152 code.shrinkAndFree(gpa, code.items.len);
165153}
166154
167155pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
168156 const tracy = trace(@src());
169157 defer tracy.end();
170158
171 const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);
159 const gpa = self.base.allocator;
160
161 const gop = try self.decl_table.getOrPut(gpa, decl_index);
172162 if (!gop.found_existing) {
173163 gop.value_ptr.* = .{};
174164 }
175 const fwd_decl = &gop.value_ptr.fwd_decl;
176165 const ctypes = &gop.value_ptr.ctypes;
177 const typedefs = &gop.value_ptr.typedefs;
166 const fwd_decl = &gop.value_ptr.fwd_decl;
178167 const code = &gop.value_ptr.code;
168 ctypes.clearRetainingCapacity(gpa);
179169 fwd_decl.shrinkRetainingCapacity(0);
180 ctypes.clearRetainingCapacity(module.gpa);
181 for (typedefs.values()) |value| {
182 module.gpa.free(value.rendered);
183 }
184 typedefs.clearRetainingCapacity();
185170 code.shrinkRetainingCapacity(0);
186171
187172 const decl = module.declPtr(decl_index);
188173
189174 var object: codegen.Object = .{
190175 .dg = .{
191 .gpa = module.gpa,
176 .gpa = gpa,
192177 .module = module,
193178 .error_msg = null,
194179 .decl_index = decl_index,
195180 .decl = decl,
196 .fwd_decl = fwd_decl.toManaged(module.gpa),
181 .fwd_decl = fwd_decl.toManaged(gpa),
197182 .ctypes = ctypes.*,
198 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
199 .typedefs_arena = self.arena.allocator(),
200183 },
201 .code = code.toManaged(module.gpa),
184 .code = code.toManaged(gpa),
202185 .indent_writer = undefined, // set later so we can get a pointer to object.code
203186 };
204187 object.indent_writer = .{ .underlying_writer = object.code.writer() };
205188 defer {
206189 object.code.deinit();
207 for (object.dg.typedefs.values()) |typedef| {
208 module.gpa.free(typedef.rendered);
209 }
210 object.dg.typedefs.deinit();
211190 object.dg.ctypes.deinit(object.dg.gpa);
212191 object.dg.fwd_decl.deinit();
213192 }
214193
215194 codegen.genDecl(&object) catch |err| switch (err) {
216195 error.AnalysisFail => {
217 try module.failed_decls.put(module.gpa, decl_index, object.dg.error_msg.?);
196 try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
218197 return;
219198 },
220199 else => |e| return e,
221200 };
222201
202 ctypes.* = object.dg.ctypes.move();
223203 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
224 ctypes.* = object.dg.ctypes;
225 object.dg.ctypes = .{};
226 typedefs.* = object.dg.typedefs.unmanaged;
227 object.dg.typedefs.unmanaged = .{};
228204 code.* = object.code.moveToUnmanaged();
229205
230206 // Free excess allocated memory for this Decl.
231 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
232 code.shrinkAndFree(module.gpa, code.items.len);
233 ctypes.shrinkAndFree(module.gpa);
207 ctypes.shrinkToFit(gpa);
208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
209 code.shrinkAndFree(gpa, code.items.len);
234210}
235211
236212pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -260,7 +236,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
260236 sub_prog_node.activate();
261237 defer sub_prog_node.end();
262238
263 const gpa = comp.gpa;
239 const gpa = self.base.allocator;
264240 const module = self.base.options.module.?;
265241
266242 // This code path happens exclusively with -ofmt=c. The flush logic for
......@@ -271,19 +247,17 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
271247
272248 const abi_define = abiDefine(comp);
273249
274 // Covers defines, zig.h, typedef, and asm.
275 var buf_count: usize = 2;
276 if (abi_define != null) buf_count += 1;
277 try f.all_buffers.ensureUnusedCapacity(gpa, buf_count);
250 // Covers defines, zig.h, ctypes, asm.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 4);
278252
279253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
280254 f.appendBufAssumeCapacity(zig_h);
281255
282 const typedef_index = f.all_buffers.items.len;
256 const ctypes_index = f.all_buffers.items.len;
283257 f.all_buffers.items.len += 1;
284258
285259 {
286 var asm_buf = f.asm_buf.toManaged(module.gpa);
260 var asm_buf = f.asm_buf.toManaged(gpa);
287261 defer asm_buf.deinit();
288262
289263 try codegen.genGlobalAsm(module, &asm_buf);
......@@ -294,7 +268,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
294268
295269 try self.flushErrDecls(&f);
296270
297 // Typedefs, forward decls, and non-functions first.
271 // `CType`s, forward decls, and non-functions first.
298272 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore
299273 // we must traverse the set of Decls that we are emitting according to their dependencies.
300274 // Our strategy is to populate a set of remaining decls, pop Decls one by one,
......@@ -321,11 +295,11 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
321295 }
322296 }
323297
324 f.all_buffers.items[typedef_index] = .{
325 .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "",
326 .iov_len = f.typedef_buf.items.len,
298 f.all_buffers.items[ctypes_index] = .{
299 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
300 .iov_len = f.ctypes_buf.items.len,
327301 };
328 f.file_size += f.typedef_buf.items.len;
302 f.file_size += f.ctypes_buf.items.len;
329303
330304 // Now the code.
331305 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);
......@@ -338,31 +312,23 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
338312}
339313
340314const Flush = struct {
341 err_decls: DeclBlock = .{},
342315 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
343316
344 ctypes: CTypes = .{},
345 typedefs: Typedefs = .{},
346 typedef_buf: std.ArrayListUnmanaged(u8) = .{},
317 ctypes: codegen.CType.Store = .{},
318 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
319 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
320
321 err_decls: DeclBlock = .{},
322
323 lazy_fns: LazyFns = .{},
324
347325 asm_buf: std.ArrayListUnmanaged(u8) = .{},
348326 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
349327 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
350328 /// Keeps track of the total bytes of `all_buffers`.
351329 file_size: u64 = 0,
352330
353 const CTypes = std.ArrayHashMapUnmanaged(
354 codegen.CType,
355 void,
356 codegen.CType.HashContext32,
357 true,
358 );
359
360 const Typedefs = std.HashMapUnmanaged(
361 Type,
362 void,
363 Type.HashContext64,
364 std.hash_map.default_max_load_percentage,
365 );
331 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, DeclBlock);
366332
367333 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
368334 if (buf.len == 0) return;
......@@ -372,11 +338,14 @@ const Flush = struct {
372338
373339 fn deinit(f: *Flush, gpa: Allocator) void {
374340 f.all_buffers.deinit(gpa);
375 f.typedef_buf.deinit(gpa);
376 f.typedefs.deinit(gpa);
341 var lazy_fns_it = f.lazy_fns.valueIterator();
342 while (lazy_fns_it.next()) |db| db.deinit(gpa);
343 f.lazy_fns.deinit(gpa);
344 f.err_decls.deinit(gpa);
345 f.ctypes_buf.deinit(gpa);
346 f.ctypes_map.deinit(gpa);
377347 f.ctypes.deinit(gpa);
378348 f.remaining_decls.deinit(gpa);
379 f.err_decls.deinit(gpa);
380349 }
381350};
382351
......@@ -384,56 +353,36 @@ const FlushDeclError = error{
384353 OutOfMemory,
385354};
386355
387fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void {
388 if (typedefs.count() == 0) return;
389 const gpa = self.base.allocator;
390 const module = self.base.options.module.?;
391
392 try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{
393 .mod = module,
394 });
395 var it = typedefs.iterator();
396 while (it.next()) |new| {
397 const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{
398 .mod = module,
399 });
400 if (!gop.found_existing) {
401 try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered);
402 }
403 }
356fn flushCTypes(self: *C, f: *Flush, ctypes: codegen.CType.Store) FlushDeclError!void {
357 _ = self;
358 _ = f;
359 _ = ctypes;
404360}
405361
406362fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
407 const module = self.base.options.module.?;
363 const gpa = self.base.allocator;
408364
409365 const fwd_decl = &f.err_decls.fwd_decl;
410366 const ctypes = &f.err_decls.ctypes;
411 const typedefs = &f.err_decls.typedefs;
412367 const code = &f.err_decls.code;
413368
414369 var object = codegen.Object{
415370 .dg = .{
416 .gpa = module.gpa,
417 .module = module,
371 .gpa = gpa,
372 .module = self.base.options.module.?,
418373 .error_msg = null,
419374 .decl_index = undefined,
420375 .decl = undefined,
421 .fwd_decl = fwd_decl.toManaged(module.gpa),
376 .fwd_decl = fwd_decl.toManaged(gpa),
422377 .ctypes = ctypes.*,
423 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
424 .typedefs_arena = self.arena.allocator(),
425378 },
426 .code = code.toManaged(module.gpa),
379 .code = code.toManaged(gpa),
427380 .indent_writer = undefined, // set later so we can get a pointer to object.code
428381 };
429382 object.indent_writer = .{ .underlying_writer = object.code.writer() };
430383 defer {
431384 object.code.deinit();
432 object.dg.ctypes.deinit(module.gpa);
433 for (object.dg.typedefs.values()) |typedef| {
434 module.gpa.free(typedef.rendered);
435 }
436 object.dg.typedefs.deinit();
385 object.dg.ctypes.deinit(gpa);
437386 object.dg.fwd_decl.deinit();
438387 }
439388
......@@ -443,16 +392,75 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
443392 };
444393
445394 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
446 typedefs.* = object.dg.typedefs.unmanaged;
447 object.dg.typedefs.unmanaged = .{};
395 ctypes.* = object.dg.ctypes.move();
396 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);
402}
403
404fn flushLazyFn(
405 self: *C,
406 f: *Flush,
407 db: *DeclBlock,
408 lazy_fn: codegen.LazyFnMap.Entry,
409) FlushDeclError!void {
410 const gpa = self.base.allocator;
411
412 const fwd_decl = &db.fwd_decl;
413 const ctypes = &db.ctypes;
414 const code = &db.code;
415
416 var object = codegen.Object{
417 .dg = .{
418 .gpa = gpa,
419 .module = self.base.options.module.?,
420 .error_msg = null,
421 .decl_index = undefined,
422 .decl = undefined,
423 .fwd_decl = fwd_decl.toManaged(gpa),
424 .ctypes = ctypes.*,
425 },
426 .code = code.toManaged(gpa),
427 .indent_writer = undefined, // set later so we can get a pointer to object.code
428 };
429 object.indent_writer = .{ .underlying_writer = object.code.writer() };
430 defer {
431 object.code.deinit();
432 object.dg.ctypes.deinit(gpa);
433 object.dg.fwd_decl.deinit();
434 }
435
436 codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {
437 error.AnalysisFail => unreachable,
438 else => |e| return e,
439 };
440
441 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
442 ctypes.* = object.dg.ctypes.move();
448443 code.* = object.code.moveToUnmanaged();
449444
450 try self.flushTypedefs(f, typedefs.*);
451 try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1);
445 try self.flushCTypes(f, ctypes.*);
446 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
452447 f.appendBufAssumeCapacity(fwd_decl.items);
453448 f.appendBufAssumeCapacity(code.items);
454449}
455450
451fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
452 const gpa = self.base.allocator;
453 try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(Flush.LazyFns.Size, lazy_fns.count()));
454
455 var it = lazy_fns.iterator();
456 while (it.next()) |entry| {
457 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
458 if (gop.found_existing) continue;
459 gop.value_ptr.* = .{};
460 try self.flushLazyFn(f, gop.value_ptr, entry);
461 }
462}
463
456464/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
457465fn flushDecl(
458466 self: *C,
......@@ -460,8 +468,8 @@ fn flushDecl(
460468 decl_index: Module.Decl.Index,
461469 export_names: std.StringHashMapUnmanaged(void),
462470) FlushDeclError!void {
463 const module = self.base.options.module.?;
464 const decl = module.declPtr(decl_index);
471 const gpa = self.base.allocator;
472 const decl = self.base.options.module.?.declPtr(decl_index);
465473 // Before flushing any particular Decl we must ensure its
466474 // dependencies are already flushed, so that the order in the .c
467475 // file comes out correctly.
......@@ -472,10 +480,10 @@ fn flushDecl(
472480 }
473481
474482 const decl_block = self.decl_table.getPtr(decl_index).?;
475 const gpa = self.base.allocator;
476483
477 try self.flushTypedefs(f, decl_block.typedefs);
478 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
484 try self.flushCTypes(f, decl_block.ctypes);
485 try self.flushLazyFns(f, decl_block.lazy_fns);
486 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
479487 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))
480488 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);
481489}