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 {...@@ -3277,14 +3277,9 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3277 .decl = decl,3277 .decl = decl,
3278 .fwd_decl = fwd_decl.toManaged(gpa),3278 .fwd_decl = fwd_decl.toManaged(gpa),
3279 .ctypes = .{},3279 .ctypes = .{},
3280 .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }),
3281 .typedefs_arena = ctypes_arena.allocator(),
3282 };3280 };
3283 defer {3281 defer {
3284 for (dg.typedefs.values()) |typedef| {3282 dg.ctypes.deinit(gpa);
3285 module.gpa.free(typedef.rendered);
3286 }
3287 dg.typedefs.deinit();
3288 dg.fwd_decl.deinit();3283 dg.fwd_decl.deinit();
3289 }3284 }
32903285
src/codegen/c.zig+88-555
...@@ -23,7 +23,7 @@ const libcFloatSuffix = target_util.libcFloatSuffix;...@@ -23,7 +23,7 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { Const, ConstArgument, Mut };26const Mutability = enum { @"const", mut };
27const BigIntLimb = std.math.big.Limb;27const BigIntLimb = std.math.big.Limb;
28const BigInt = std.math.big.int;28const BigInt = std.math.big.int;
2929
...@@ -63,12 +63,17 @@ const TypedefKind = enum {...@@ -63,12 +63,17 @@ const TypedefKind = enum {
63};63};
6464
65pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);65pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
66pub const TypedefMap = std.ArrayHashMap(66
67 Type,67pub const LazyFnKey = union(enum) {
68 struct { name: []const u8, rendered: []u8 },68 tag_name: Decl.Index,
69 Type.HashContext32,69};
70 true,70pub const LazyFnValue = struct {
71);71 fn_name: []const u8,
72 data: union {
73 tag_name: Type,
74 },
75};
76pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
7277
73const LoopDepth = u16;78const LoopDepth = u16;
74const Local = struct {79const Local = struct {
...@@ -83,11 +88,6 @@ const LocalsList = std.ArrayListUnmanaged(LocalIndex);...@@ -83,11 +88,6 @@ const LocalsList = std.ArrayListUnmanaged(LocalIndex);
83const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);88const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);
84const LocalsStack = std.ArrayListUnmanaged(LocalsMap);89const LocalsStack = std.ArrayListUnmanaged(LocalsMap);
8590
86const FormatTypeAsCIdentContext = struct {
87 ty: Type,
88 mod: *Module,
89};
90
91const ValueRenderLocation = enum {91const ValueRenderLocation = enum {
92 FunctionArgument,92 FunctionArgument,
93 Initializer,93 Initializer,
...@@ -108,26 +108,6 @@ const BuiltinInfo = enum {...@@ -108,26 +108,6 @@ const BuiltinInfo = enum {
108 Bits,108 Bits,
109};109};
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
131const reserved_idents = std.ComptimeStringMap(void, .{111const reserved_idents = std.ComptimeStringMap(void, .{
132 // C language112 // C language
133 .{ "alignas", {113 .{ "alignas", {
...@@ -283,6 +263,7 @@ pub const Function = struct {...@@ -283,6 +263,7 @@ pub const Function = struct {
283 next_arg_index: usize = 0,263 next_arg_index: usize = 0,
284 next_block_index: usize = 0,264 next_block_index: usize = 0,
285 object: Object,265 object: Object,
266 lazy_fns: LazyFnMap,
286 func: *Module.Fn,267 func: *Module.Fn,
287 /// All the locals, to be emitted at the top of the function.268 /// All the locals, to be emitted at the top of the function.
288 locals: std.ArrayListUnmanaged(Local) = .{},269 locals: std.ArrayListUnmanaged(Local) = .{},
...@@ -319,7 +300,7 @@ pub const Function = struct {...@@ -319,7 +300,7 @@ pub const Function = struct {
319 const gpa = f.object.dg.gpa;300 const gpa = f.object.dg.gpa;
320 try f.allocs.put(gpa, decl_c_value.local, true);301 try f.allocs.put(gpa, decl_c_value.local, true);
321 try writer.writeAll("static ");302 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);
323 try writer.writeAll(" = ");304 try writer.writeAll(" = ");
324 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);305 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
325 try writer.writeAll(";\n ");306 try writer.writeAll(";\n ");
...@@ -353,7 +334,7 @@ pub const Function = struct {...@@ -353,7 +334,7 @@ pub const Function = struct {
353 }334 }
354335
355 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {336 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);
357 log.debug("%{d}: allocating t{d}", .{ inst, result.local });338 log.debug("%{d}: allocating t{d}", .{ inst, result.local });
358 return result;339 return result;
359 }340 }
...@@ -448,6 +429,29 @@ pub const Function = struct {...@@ -448,6 +429,29 @@ pub const Function = struct {
448 return f.object.dg.fmtIntLiteral(ty, val);429 return f.object.dg.fmtIntLiteral(ty, val);
449 }430 }
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
451 pub fn deinit(f: *Function) void {455 pub fn deinit(f: *Function) void {
452 const gpa = f.object.dg.gpa;456 const gpa = f.object.dg.gpa;
453 f.allocs.deinit(gpa);457 f.allocs.deinit(gpa);
...@@ -458,11 +462,8 @@ pub const Function = struct {...@@ -458,11 +462,8 @@ pub const Function = struct {
458 f.free_locals_stack.deinit(gpa);462 f.free_locals_stack.deinit(gpa);
459 f.blocks.deinit(gpa);463 f.blocks.deinit(gpa);
460 f.value_map.deinit();464 f.value_map.deinit();
465 f.lazy_fns.deinit(gpa);
461 f.object.code.deinit();466 f.object.code.deinit();
462 for (f.object.dg.typedefs.values()) |typedef| {
463 gpa.free(typedef.rendered);
464 }
465 f.object.dg.typedefs.deinit();
466 f.object.dg.ctypes.deinit(gpa);467 f.object.dg.ctypes.deinit(gpa);
467 f.object.dg.fwd_decl.deinit();468 f.object.dg.fwd_decl.deinit();
468 f.arena.deinit();469 f.arena.deinit();
...@@ -492,9 +493,6 @@ pub const DeclGen = struct {...@@ -492,9 +493,6 @@ pub const DeclGen = struct {
492 fwd_decl: std.ArrayList(u8),493 fwd_decl: std.ArrayList(u8),
493 error_msg: ?*Module.ErrorMsg,494 error_msg: ?*Module.ErrorMsg,
494 ctypes: CType.Store,495 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
499 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {497 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
500 @setCold(true);498 @setCold(true);
...@@ -504,14 +502,6 @@ pub const DeclGen = struct {...@@ -504,14 +502,6 @@ pub const DeclGen = struct {
504 return error.AnalysisFail;502 return error.AnalysisFail;
505 }503 }
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
515 fn renderDeclValue(505 fn renderDeclValue(
516 dg: *DeclGen,506 dg: *DeclGen,
517 writer: anytype,507 writer: anytype,
...@@ -1493,7 +1483,7 @@ pub const DeclGen = struct {...@@ -1493,7 +1483,7 @@ pub const DeclGen = struct {
1493 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1483 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1494 if (index > 0) try w.writeAll(", ");1484 if (index > 0) try w.writeAll(", ");
1495 const name = CValue{ .arg = index };1485 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);
1497 index += 1;1487 index += 1;
1498 }1488 }
14991489
...@@ -1507,453 +1497,6 @@ pub const DeclGen = struct {...@@ -1507,453 +1497,6 @@ pub const DeclGen = struct {
1507 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});1497 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1508 }1498 }
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
1957 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {1500 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1958 return dg.ctypes.indexToCType(idx);1501 return dg.ctypes.indexToCType(idx);
1959 }1502 }
...@@ -2408,31 +1951,27 @@ pub const DeclGen = struct {...@@ -2408,31 +1951,27 @@ pub const DeclGen = struct {
2408 const idx = try dg.typeToIndex(ty);1951 const idx = try dg.typeToIndex(ty);
2409 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{1952 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{
2410 .@"const" = switch (mutability) {1953 .@"const" = switch (mutability) {
2411 .Const, .ConstArgument => true,1954 .mut => false,
2412 .Mut => false,1955 .@"const" => true,
2413 },1956 },
2414 }))});1957 }))});
2415 try dg.writeCValue(w, name);1958 try dg.writeCValue(w, name);
2416 try dg.renderTypeSuffix(w, idx, .suffix);1959 try dg.renderTypeSuffix(w, idx, .suffix);
2417 }1960 }
24181961
2419 fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1962 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
2420 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
2421 defer buffer.deinit();
2422 const bw = buffer.writer();
2423
2424 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);1963 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
24251964
2426 try buffer.appendSlice("static ");1965 try w.writeAll("static ");
2427 try dg.renderType(bw, name_slice_ty, .Complete);1966 try dg.renderType(w, name_slice_ty, .Complete);
2428 const name_begin = buffer.items.len + " ".len;1967 try w.writeByte(' ');
2429 try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) });1968 try w.writeAll(fn_name);
2430 const name_end = buffer.items.len - "(".len;1969 try w.writeByte('(');
2431 try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);1970 try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete);
2432 try buffer.appendSlice(") {\n switch (tag) {\n");1971 try w.writeAll(") {\n switch (tag) {\n");
2433 for (enum_ty.enumFields().keys(), 0..) |name, index| {1972 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2434 const name_z = try dg.typedefs.allocator.dupeZ(u8, name);1973 const name_z = try dg.gpa.dupeZ(u8, name);
2435 defer dg.typedefs.allocator.free(name_z);1974 defer dg.gpa.free(name_z);
2436 const name_bytes = name_z[0 .. name_z.len + 1];1975 const name_bytes = name_z[0 .. name_z.len + 1];
24371976
2438 var tag_pl: Value.Payload.U32 = .{1977 var tag_pl: Value.Payload.U32 = .{
...@@ -2453,40 +1992,23 @@ pub const DeclGen = struct {...@@ -2453,40 +1992,23 @@ pub const DeclGen = struct {
2453 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };1992 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2454 const len_val = Value.initPayload(&len_pl.base);1993 const len_val = Value.initPayload(&len_pl.base);
24551994
2456 try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});1995 try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
2457 try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete);1996 try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete);
2458 try buffer.appendSlice(" = ");1997 try w.writeAll(" = ");
2459 try dg.renderValue(bw, name_ty, name_val, .Initializer);1998 try dg.renderValue(w, name_ty, name_val, .Initializer);
2460 try buffer.appendSlice(";\n return (");1999 try w.writeAll(";\n return (");
2461 try dg.renderTypecast(bw, name_slice_ty);2000 try dg.renderTypecast(w, name_slice_ty);
2462 try bw.print("){{{}, {}}};\n", .{2001 try w.print("){{{}, {}}};\n", .{
2463 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),2002 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
2464 });2003 });
24652004
2466 try buffer.appendSlice(" }\n");2005 try w.writeAll(" }\n");
2467 }2006 }
2468 try buffer.appendSlice(" }\n while (");2007 try w.writeAll(" }\n while (");
2469 try dg.renderValue(bw, Type.bool, Value.true, .Other);2008 try dg.renderValue(w, Type.bool, Value.true, .Other);
2470 try buffer.appendSlice(") ");2009 try w.writeAll(") ");
2471 _ = try airBreakpoint(bw);2010 _ = try airBreakpoint(w);
2472 try buffer.appendSlice("}\n");2011 try w.writeAll("}\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);
2490 }2012 }
24912013
2492 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {2014 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
...@@ -2724,7 +2246,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2724,7 +2246,7 @@ pub fn genErrDecls(o: *Object) !void {
2724 const name_val = Value.initPayload(&name_pl.base);2246 const name_val = Value.initPayload(&name_pl.base);
27252247
2726 try writer.writeAll("static ");2248 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);
2728 try writer.writeAll(" = ");2250 try writer.writeAll(" = ");
2729 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);2251 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
2730 try writer.writeAll(";\n");2252 try writer.writeAll(";\n");
...@@ -2737,7 +2259,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2737,7 +2259,7 @@ pub fn genErrDecls(o: *Object) !void {
2737 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);2259 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
27382260
2739 try writer.writeAll("static ");2261 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);
2741 try writer.writeAll(" = {");2263 try writer.writeAll(" = {");
2742 for (o.dg.module.error_name_list.items, 0..) |name, value| {2264 for (o.dg.module.error_name_list.items, 0..) |name, value| {
2743 if (value != 0) try writer.writeByte(',');2265 if (value != 0) try writer.writeByte(',');
...@@ -2767,6 +2289,17 @@ fn genExports(o: *Object) !void {...@@ -2767,6 +2289,17 @@ fn genExports(o: *Object) !void {
2767 };2289 };
2768}2290}
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
2770pub fn genFunc(f: *Function) !void {2303pub fn genFunc(f: *Function) !void {
2771 const tracy = trace(@src());2304 const tracy = trace(@src());
2772 defer tracy.end();2305 defer tracy.end();
...@@ -2845,7 +2378,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2845,7 +2378,7 @@ pub fn genFunc(f: *Function) !void {
2845 w,2378 w,
2846 local.ty,2379 local.ty,
2847 .{ .local = local_index },2380 .{ .local = local_index },
2848 .Mut,2381 .mut,
2849 local.alignment,2382 local.alignment,
2850 .Complete,2383 .Complete,
2851 );2384 );
...@@ -2886,7 +2419,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2886,7 +2419,7 @@ pub fn genDecl(o: *Object) !void {
28862419
2887 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2420 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2888 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");2421 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);
2890 try fwd_decl_writer.writeAll(";\n");2423 try fwd_decl_writer.writeAll(";\n");
2891 try genExports(o);2424 try genExports(o);
28922425
...@@ -2896,7 +2429,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2896,7 +2429,7 @@ pub fn genDecl(o: *Object) !void {
2896 if (!is_global) try w.writeAll("static ");2429 if (!is_global) try w.writeAll("static ");
2897 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2430 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2898 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2431 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);
2900 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");2433 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");
2901 try w.writeAll(" = ");2434 try w.writeAll(" = ");
2902 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);2435 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
...@@ -2908,13 +2441,13 @@ pub fn genDecl(o: *Object) !void {...@@ -2908,13 +2441,13 @@ pub fn genDecl(o: *Object) !void {
2908 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };2441 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
29092442
2910 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2443 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);
2912 try fwd_decl_writer.writeAll(";\n");2445 try fwd_decl_writer.writeAll(";\n");
29132446
2914 const w = o.writer();2447 const w = o.writer();
2915 if (!is_global) try w.writeAll("static ");2448 if (!is_global) try w.writeAll("static ");
2916 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2449 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);
2918 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");2451 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");
2919 try w.writeAll(" = ");2452 try w.writeAll(" = ");
2920 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2453 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
...@@ -3443,7 +2976,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3443,7 +2976,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3443 return CValue{ .undef = inst_ty };2976 return CValue{ .undef = inst_ty };
3444 }2977 }
34452978
3446 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;2979 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3447 const target = f.object.dg.module.getTarget();2980 const target = f.object.dg.module.getTarget();
3448 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));2981 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
3449 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });2982 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
...@@ -3460,7 +2993,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3460,7 +2993,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3460 return CValue{ .undef = inst_ty };2993 return CValue{ .undef = inst_ty };
3461 }2994 }
34622995
3463 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;2996 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3464 const target = f.object.dg.module.getTarget();2997 const target = f.object.dg.module.getTarget();
3465 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));2998 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
3466 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });2999 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
...@@ -4937,7 +4470,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4937,7 +4470,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4937 writer,4470 writer,
4938 output_ty,4471 output_ty,
4939 local_value,4472 local_value,
4940 .Mut,4473 .mut,
4941 alignment,4474 alignment,
4942 .Complete,4475 .Complete,
4943 );4476 );
...@@ -4976,7 +4509,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4976,7 +4509,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4976 writer,4509 writer,
4977 input_ty,4510 input_ty,
4978 local_value,4511 local_value,
4979 .Const,4512 .@"const",
4980 alignment,4513 alignment,
4981 .Complete,4514 .Complete,
4982 );4515 );
...@@ -6474,7 +6007,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6474,7 +6007,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6474 const writer = f.object.writer();6007 const writer = f.object.writer();
6475 const local = try f.allocLocal(inst, inst_ty);6008 const local = try f.allocLocal(inst, inst_ty);
6476 try f.writeCValue(writer, local, .Other);6009 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)});
6478 try f.writeCValue(writer, operand, .Other);6011 try f.writeCValue(writer, operand, .Other);
6479 try writer.writeAll(");\n");6012 try writer.writeAll(");\n");
64806013
src/codegen/c/type.zig+11-11
...@@ -290,11 +290,11 @@ pub const CType = extern union {...@@ -290,11 +290,11 @@ pub const CType = extern union {
290 }290 }
291 };291 };
292292
293 const Promoted = struct {293 pub const Promoted = struct {
294 arena: std.heap.ArenaAllocator,294 arena: std.heap.ArenaAllocator,
295 set: Set,295 set: Set,
296296
297 fn gpa(self: *Promoted) Allocator {297 pub fn gpa(self: *Promoted) Allocator {
298 return self.arena.child_allocator;298 return self.arena.child_allocator;
299 }299 }
300300
...@@ -345,11 +345,11 @@ pub const CType = extern union {...@@ -345,11 +345,11 @@ pub const CType = extern union {
345 }345 }
346 };346 };
347347
348 fn promote(self: Store, gpa: Allocator) Promoted {348 pub fn promote(self: Store, gpa: Allocator) Promoted {
349 return .{ .arena = self.arena.promote(gpa), .set = self.set };349 return .{ .arena = self.arena.promote(gpa), .set = self.set };
350 }350 }
351351
352 fn demote(self: *Store, promoted: Promoted) void {352 pub fn demote(self: *Store, promoted: Promoted) void {
353 self.arena = promoted.arena.state;353 self.arena = promoted.arena.state;
354 self.set = promoted.set;354 self.set = promoted.set;
355 }355 }
...@@ -382,17 +382,17 @@ pub const CType = extern union {...@@ -382,17 +382,17 @@ pub const CType = extern union {
382 _ = promoted.arena.reset(.retain_capacity);382 _ = promoted.arena.reset(.retain_capacity);
383 }383 }
384384
385 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {385 pub fn clearAndFree(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 {
390 var promoted = self.promote(gpa);386 var promoted = self.promote(gpa);
391 defer self.demote(promoted);387 defer self.demote(promoted);
392 promoted.set.map.clearAndFree(gpa);388 promoted.set.map.clearAndFree(gpa);
393 _ = promoted.arena.reset(.free_all);389 _ = promoted.arena.reset(.free_all);
394 }390 }
395391
392 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {
393 self.set.map.shrinkAndFree(gpa, self.set.map.count());
394 }
395
396 pub fn move(self: *Store) Store {396 pub fn move(self: *Store) Store {
397 const moved = self.*;397 const moved = self.*;
398 self.* = .{};398 self.* = .{};
...@@ -1252,8 +1252,8 @@ pub const CType = extern union {...@@ -1252,8 +1252,8 @@ pub const CType = extern union {
1252 pub const HashContext64 = struct {1252 pub const HashContext64 = struct {
1253 store: *const Store.Set,1253 store: *const Store.Set,
12541254
1255 pub fn hash(_: @This(), cty: CType) u64 {1255 pub fn hash(self: @This(), cty: CType) u64 {
1256 return cty.hash();1256 return cty.hash(self.store.*);
1257 }1257 }
1258 pub fn eql(_: @This(), lhs: CType, rhs: CType) bool {1258 pub fn eql(_: @This(), lhs: CType, rhs: CType) bool {
1259 return lhs.eql(rhs);1259 return lhs.eql(rhs);
src/link/C.zig+141-133
...@@ -22,26 +22,19 @@ base: link.File,...@@ -22,26 +22,19 @@ base: link.File,
22/// Instead, it tracks all declarations in this table, and iterates over it22/// Instead, it tracks all declarations in this table, and iterates over it
23/// in the flush function, stitching pre-rendered pieces of C code together.23/// in the flush function, stitching pre-rendered pieces of C code together.
24decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},24decl_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
29/// Per-declaration data.26/// Per-declaration data.
30const DeclBlock = struct {27const DeclBlock = struct {
31 code: std.ArrayListUnmanaged(u8) = .{},28 code: std.ArrayListUnmanaged(u8) = .{},
32 fwd_decl: std.ArrayListUnmanaged(u8) = .{},29 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.
33 ctypes: codegen.CType.Store = .{},32 ctypes: codegen.CType.Store = .{},
34 /// Each Decl stores a mapping of Zig Types to corresponding C types, for every33 /// Key and Value storage use the ctype arena.
35 /// Zig Type used by the Decl. In flush(), we iterate over each Decl34 lazy_fns: codegen.LazyFnMap = .{},
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 = .{},
3935
40 fn deinit(db: *DeclBlock, gpa: Allocator) void {36 fn deinit(db: *DeclBlock, gpa: Allocator) void {
41 for (db.typedefs.values()) |typedef| {37 db.lazy_fns.deinit(gpa);
42 gpa.free(typedef.rendered);
43 }
44 db.typedefs.deinit(gpa);
45 db.ctypes.deinit(gpa);38 db.ctypes.deinit(gpa);
46 db.fwd_decl.deinit(gpa);39 db.fwd_decl.deinit(gpa);
47 db.code.deinit(gpa);40 db.code.deinit(gpa);
...@@ -66,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C...@@ -66,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
66 errdefer gpa.destroy(c_file);59 errdefer gpa.destroy(c_file);
6760
68 c_file.* = C{61 c_file.* = C{
69 .arena = std.heap.ArenaAllocator.init(gpa),
70 .base = .{62 .base = .{
71 .tag = .c,63 .tag = .c,
72 .options = options,64 .options = options,
...@@ -85,8 +77,6 @@ pub fn deinit(self: *C) void {...@@ -85,8 +77,6 @@ pub fn deinit(self: *C) void {
85 db.deinit(gpa);77 db.deinit(gpa);
86 }78 }
87 self.decl_table.deinit(gpa);79 self.decl_table.deinit(gpa);
88
89 self.arena.deinit();
90}80}
9181
92pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {82pub 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...@@ -101,44 +91,42 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
101 const tracy = trace(@src());91 const tracy = trace(@src());
102 defer tracy.end();92 defer tracy.end();
10393
94 const gpa = self.base.allocator;
95
104 const decl_index = func.owner_decl;96 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);
106 if (!gop.found_existing) {98 if (!gop.found_existing) {
107 gop.value_ptr.* = .{};99 gop.value_ptr.* = .{};
108 }100 }
109 const fwd_decl = &gop.value_ptr.fwd_decl;
110 const ctypes = &gop.value_ptr.ctypes;101 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;
112 const code = &gop.value_ptr.code;104 const code = &gop.value_ptr.code;
105 ctypes.clearRetainingCapacity(gpa);
106 lazy_fns.clearRetainingCapacity();
113 fwd_decl.shrinkRetainingCapacity(0);107 fwd_decl.shrinkRetainingCapacity(0);
114 ctypes.clearRetainingCapacity(module.gpa);
115 for (typedefs.values()) |typedef| {
116 module.gpa.free(typedef.rendered);
117 }
118 typedefs.clearRetainingCapacity();
119 code.shrinkRetainingCapacity(0);108 code.shrinkRetainingCapacity(0);
120109
121 var function: codegen.Function = .{110 var function: codegen.Function = .{
122 .value_map = codegen.CValueMap.init(module.gpa),111 .value_map = codegen.CValueMap.init(gpa),
123 .air = air,112 .air = air,
124 .liveness = liveness,113 .liveness = liveness,
125 .func = func,114 .func = func,
126 .object = .{115 .object = .{
127 .dg = .{116 .dg = .{
128 .gpa = module.gpa,117 .gpa = gpa,
129 .module = module,118 .module = module,
130 .error_msg = null,119 .error_msg = null,
131 .decl_index = decl_index,120 .decl_index = decl_index,
132 .decl = module.declPtr(decl_index),121 .decl = module.declPtr(decl_index),
133 .fwd_decl = fwd_decl.toManaged(module.gpa),122 .fwd_decl = fwd_decl.toManaged(gpa),
134 .ctypes = ctypes.*,123 .ctypes = ctypes.*,
135 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
136 .typedefs_arena = self.arena.allocator(),
137 },124 },
138 .code = code.toManaged(module.gpa),125 .code = code.toManaged(gpa),
139 .indent_writer = undefined, // set later so we can get a pointer to object.code126 .indent_writer = undefined, // set later so we can get a pointer to object.code
140 },127 },
141 .arena = std.heap.ArenaAllocator.init(module.gpa),128 .lazy_fns = lazy_fns.*,
129 .arena = std.heap.ArenaAllocator.init(gpa),
142 };130 };
143131
144 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };132 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...@@ -146,91 +134,79 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
146134
147 codegen.genFunc(&function) catch |err| switch (err) {135 codegen.genFunc(&function) catch |err| switch (err) {
148 error.AnalysisFail => {136 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.?);
150 return;138 return;
151 },139 },
152 else => |e| return e,140 else => |e| return e,
153 };141 };
154142
155 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
156 ctypes.* = function.object.dg.ctypes.move();143 ctypes.* = function.object.dg.ctypes.move();
157 typedefs.* = function.object.dg.typedefs.unmanaged;144 lazy_fns.* = function.lazy_fns.move();
158 function.object.dg.typedefs.unmanaged = .{};145 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
159 code.* = function.object.code.moveToUnmanaged();146 code.* = function.object.code.moveToUnmanaged();
160147
161 // Free excess allocated memory for this Decl.148 // Free excess allocated memory for this Decl.
162 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);149 ctypes.shrinkToFit(gpa);
163 code.shrinkAndFree(module.gpa, code.items.len);150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
164 ctypes.shrinkAndFree(module.gpa);151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
152 code.shrinkAndFree(gpa, code.items.len);
165}153}
166154
167pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {155pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
168 const tracy = trace(@src());156 const tracy = trace(@src());
169 defer tracy.end();157 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);
172 if (!gop.found_existing) {162 if (!gop.found_existing) {
173 gop.value_ptr.* = .{};163 gop.value_ptr.* = .{};
174 }164 }
175 const fwd_decl = &gop.value_ptr.fwd_decl;
176 const ctypes = &gop.value_ptr.ctypes;165 const ctypes = &gop.value_ptr.ctypes;
177 const typedefs = &gop.value_ptr.typedefs;166 const fwd_decl = &gop.value_ptr.fwd_decl;
178 const code = &gop.value_ptr.code;167 const code = &gop.value_ptr.code;
168 ctypes.clearRetainingCapacity(gpa);
179 fwd_decl.shrinkRetainingCapacity(0);169 fwd_decl.shrinkRetainingCapacity(0);
180 ctypes.clearRetainingCapacity(module.gpa);
181 for (typedefs.values()) |value| {
182 module.gpa.free(value.rendered);
183 }
184 typedefs.clearRetainingCapacity();
185 code.shrinkRetainingCapacity(0);170 code.shrinkRetainingCapacity(0);
186171
187 const decl = module.declPtr(decl_index);172 const decl = module.declPtr(decl_index);
188173
189 var object: codegen.Object = .{174 var object: codegen.Object = .{
190 .dg = .{175 .dg = .{
191 .gpa = module.gpa,176 .gpa = gpa,
192 .module = module,177 .module = module,
193 .error_msg = null,178 .error_msg = null,
194 .decl_index = decl_index,179 .decl_index = decl_index,
195 .decl = decl,180 .decl = decl,
196 .fwd_decl = fwd_decl.toManaged(module.gpa),181 .fwd_decl = fwd_decl.toManaged(gpa),
197 .ctypes = ctypes.*,182 .ctypes = ctypes.*,
198 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
199 .typedefs_arena = self.arena.allocator(),
200 },183 },
201 .code = code.toManaged(module.gpa),184 .code = code.toManaged(gpa),
202 .indent_writer = undefined, // set later so we can get a pointer to object.code185 .indent_writer = undefined, // set later so we can get a pointer to object.code
203 };186 };
204 object.indent_writer = .{ .underlying_writer = object.code.writer() };187 object.indent_writer = .{ .underlying_writer = object.code.writer() };
205 defer {188 defer {
206 object.code.deinit();189 object.code.deinit();
207 for (object.dg.typedefs.values()) |typedef| {
208 module.gpa.free(typedef.rendered);
209 }
210 object.dg.typedefs.deinit();
211 object.dg.ctypes.deinit(object.dg.gpa);190 object.dg.ctypes.deinit(object.dg.gpa);
212 object.dg.fwd_decl.deinit();191 object.dg.fwd_decl.deinit();
213 }192 }
214193
215 codegen.genDecl(&object) catch |err| switch (err) {194 codegen.genDecl(&object) catch |err| switch (err) {
216 error.AnalysisFail => {195 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.?);
218 return;197 return;
219 },198 },
220 else => |e| return e,199 else => |e| return e,
221 };200 };
222201
202 ctypes.* = object.dg.ctypes.move();
223 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();203 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 = .{};
228 code.* = object.code.moveToUnmanaged();204 code.* = object.code.moveToUnmanaged();
229205
230 // Free excess allocated memory for this Decl.206 // Free excess allocated memory for this Decl.
231 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);207 ctypes.shrinkToFit(gpa);
232 code.shrinkAndFree(module.gpa, code.items.len);208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
233 ctypes.shrinkAndFree(module.gpa);209 code.shrinkAndFree(gpa, code.items.len);
234}210}
235211
236pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {212pub 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)...@@ -260,7 +236,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
260 sub_prog_node.activate();236 sub_prog_node.activate();
261 defer sub_prog_node.end();237 defer sub_prog_node.end();
262238
263 const gpa = comp.gpa;239 const gpa = self.base.allocator;
264 const module = self.base.options.module.?;240 const module = self.base.options.module.?;
265241
266 // This code path happens exclusively with -ofmt=c. The flush logic for242 // 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)...@@ -271,19 +247,17 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
271247
272 const abi_define = abiDefine(comp);248 const abi_define = abiDefine(comp);
273249
274 // Covers defines, zig.h, typedef, and asm.250 // Covers defines, zig.h, ctypes, asm.
275 var buf_count: usize = 2;251 try f.all_buffers.ensureUnusedCapacity(gpa, 4);
276 if (abi_define != null) buf_count += 1;
277 try f.all_buffers.ensureUnusedCapacity(gpa, buf_count);
278252
279 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
280 f.appendBufAssumeCapacity(zig_h);254 f.appendBufAssumeCapacity(zig_h);
281255
282 const typedef_index = f.all_buffers.items.len;256 const ctypes_index = f.all_buffers.items.len;
283 f.all_buffers.items.len += 1;257 f.all_buffers.items.len += 1;
284258
285 {259 {
286 var asm_buf = f.asm_buf.toManaged(module.gpa);260 var asm_buf = f.asm_buf.toManaged(gpa);
287 defer asm_buf.deinit();261 defer asm_buf.deinit();
288262
289 try codegen.genGlobalAsm(module, &asm_buf);263 try codegen.genGlobalAsm(module, &asm_buf);
...@@ -294,7 +268,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -294,7 +268,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
294268
295 try self.flushErrDecls(&f);269 try self.flushErrDecls(&f);
296270
297 // Typedefs, forward decls, and non-functions first.271 // `CType`s, forward decls, and non-functions first.
298 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore272 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore
299 // we must traverse the set of Decls that we are emitting according to their dependencies.273 // we must traverse the set of Decls that we are emitting according to their dependencies.
300 // Our strategy is to populate a set of remaining decls, pop Decls one by one,274 // 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)...@@ -321,11 +295,11 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
321 }295 }
322 }296 }
323297
324 f.all_buffers.items[typedef_index] = .{298 f.all_buffers.items[ctypes_index] = .{
325 .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "",299 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
326 .iov_len = f.typedef_buf.items.len,300 .iov_len = f.ctypes_buf.items.len,
327 };301 };
328 f.file_size += f.typedef_buf.items.len;302 f.file_size += f.ctypes_buf.items.len;
329303
330 // Now the code.304 // Now the code.
331 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);305 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)...@@ -338,31 +312,23 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
338}312}
339313
340const Flush = struct {314const Flush = struct {
341 err_decls: DeclBlock = .{},
342 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},315 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
343316
344 ctypes: CTypes = .{},317 ctypes: codegen.CType.Store = .{},
345 typedefs: Typedefs = .{},318 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
346 typedef_buf: std.ArrayListUnmanaged(u8) = .{},319 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
320
321 err_decls: DeclBlock = .{},
322
323 lazy_fns: LazyFns = .{},
324
347 asm_buf: std.ArrayListUnmanaged(u8) = .{},325 asm_buf: std.ArrayListUnmanaged(u8) = .{},
348 /// We collect a list of buffers to write, and write them all at once with pwritev 😎326 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
349 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},327 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
350 /// Keeps track of the total bytes of `all_buffers`.328 /// Keeps track of the total bytes of `all_buffers`.
351 file_size: u64 = 0,329 file_size: u64 = 0,
352330
353 const CTypes = std.ArrayHashMapUnmanaged(331 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, DeclBlock);
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 );
366332
367 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {333 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
368 if (buf.len == 0) return;334 if (buf.len == 0) return;
...@@ -372,11 +338,14 @@ const Flush = struct {...@@ -372,11 +338,14 @@ const Flush = struct {
372338
373 fn deinit(f: *Flush, gpa: Allocator) void {339 fn deinit(f: *Flush, gpa: Allocator) void {
374 f.all_buffers.deinit(gpa);340 f.all_buffers.deinit(gpa);
375 f.typedef_buf.deinit(gpa);341 var lazy_fns_it = f.lazy_fns.valueIterator();
376 f.typedefs.deinit(gpa);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);
377 f.ctypes.deinit(gpa);347 f.ctypes.deinit(gpa);
378 f.remaining_decls.deinit(gpa);348 f.remaining_decls.deinit(gpa);
379 f.err_decls.deinit(gpa);
380 }349 }
381};350};
382351
...@@ -384,56 +353,36 @@ const FlushDeclError = error{...@@ -384,56 +353,36 @@ const FlushDeclError = error{
384 OutOfMemory,353 OutOfMemory,
385};354};
386355
387fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void {356fn flushCTypes(self: *C, f: *Flush, ctypes: codegen.CType.Store) FlushDeclError!void {
388 if (typedefs.count() == 0) return;357 _ = self;
389 const gpa = self.base.allocator;358 _ = f;
390 const module = self.base.options.module.?;359 _ = ctypes;
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 }
404}360}
405361
406fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {362fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
407 const module = self.base.options.module.?;363 const gpa = self.base.allocator;
408364
409 const fwd_decl = &f.err_decls.fwd_decl;365 const fwd_decl = &f.err_decls.fwd_decl;
410 const ctypes = &f.err_decls.ctypes;366 const ctypes = &f.err_decls.ctypes;
411 const typedefs = &f.err_decls.typedefs;
412 const code = &f.err_decls.code;367 const code = &f.err_decls.code;
413368
414 var object = codegen.Object{369 var object = codegen.Object{
415 .dg = .{370 .dg = .{
416 .gpa = module.gpa,371 .gpa = gpa,
417 .module = module,372 .module = self.base.options.module.?,
418 .error_msg = null,373 .error_msg = null,
419 .decl_index = undefined,374 .decl_index = undefined,
420 .decl = undefined,375 .decl = undefined,
421 .fwd_decl = fwd_decl.toManaged(module.gpa),376 .fwd_decl = fwd_decl.toManaged(gpa),
422 .ctypes = ctypes.*,377 .ctypes = ctypes.*,
423 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),
424 .typedefs_arena = self.arena.allocator(),
425 },378 },
426 .code = code.toManaged(module.gpa),379 .code = code.toManaged(gpa),
427 .indent_writer = undefined, // set later so we can get a pointer to object.code380 .indent_writer = undefined, // set later so we can get a pointer to object.code
428 };381 };
429 object.indent_writer = .{ .underlying_writer = object.code.writer() };382 object.indent_writer = .{ .underlying_writer = object.code.writer() };
430 defer {383 defer {
431 object.code.deinit();384 object.code.deinit();
432 object.dg.ctypes.deinit(module.gpa);385 object.dg.ctypes.deinit(gpa);
433 for (object.dg.typedefs.values()) |typedef| {
434 module.gpa.free(typedef.rendered);
435 }
436 object.dg.typedefs.deinit();
437 object.dg.fwd_decl.deinit();386 object.dg.fwd_decl.deinit();
438 }387 }
439388
...@@ -443,16 +392,75 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {...@@ -443,16 +392,75 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
443 };392 };
444393
445 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();394 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
446 typedefs.* = object.dg.typedefs.unmanaged;395 ctypes.* = object.dg.ctypes.move();
447 object.dg.typedefs.unmanaged = .{};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();
448 code.* = object.code.moveToUnmanaged();443 code.* = object.code.moveToUnmanaged();
449444
450 try self.flushTypedefs(f, typedefs.*);445 try self.flushCTypes(f, ctypes.*);
451 try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1);446 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
452 f.appendBufAssumeCapacity(fwd_decl.items);447 f.appendBufAssumeCapacity(fwd_decl.items);
453 f.appendBufAssumeCapacity(code.items);448 f.appendBufAssumeCapacity(code.items);
454}449}
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
456/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.464/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
457fn flushDecl(465fn flushDecl(
458 self: *C,466 self: *C,
...@@ -460,8 +468,8 @@ fn flushDecl(...@@ -460,8 +468,8 @@ fn flushDecl(
460 decl_index: Module.Decl.Index,468 decl_index: Module.Decl.Index,
461 export_names: std.StringHashMapUnmanaged(void),469 export_names: std.StringHashMapUnmanaged(void),
462) FlushDeclError!void {470) FlushDeclError!void {
463 const module = self.base.options.module.?;471 const gpa = self.base.allocator;
464 const decl = module.declPtr(decl_index);472 const decl = self.base.options.module.?.declPtr(decl_index);
465 // Before flushing any particular Decl we must ensure its473 // Before flushing any particular Decl we must ensure its
466 // dependencies are already flushed, so that the order in the .c474 // dependencies are already flushed, so that the order in the .c
467 // file comes out correctly.475 // file comes out correctly.
...@@ -472,10 +480,10 @@ fn flushDecl(...@@ -472,10 +480,10 @@ fn flushDecl(
472 }480 }
473481
474 const decl_block = self.decl_table.getPtr(decl_index).?;482 const decl_block = self.decl_table.getPtr(decl_index).?;
475 const gpa = self.base.allocator;
476483
477 try self.flushTypedefs(f, decl_block.typedefs);484 try self.flushCTypes(f, decl_block.ctypes);
478 try f.all_buffers.ensureUnusedCapacity(gpa, 2);485 try self.flushLazyFns(f, decl_block.lazy_fns);
486 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
479 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))487 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))
480 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);488 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);
481}489}