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

CBE: use CType for type definitions


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

src/Compilation.zig+1-1
...@@ -3273,7 +3273,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3273,7 +3273,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3273 .gpa = gpa,3273 .gpa = gpa,
3274 .module = module,3274 .module = module,
3275 .error_msg = null,3275 .error_msg = null,
3276 .decl_index = decl_index,3276 .decl_index = decl_index.toOptional(),
3277 .decl = decl,3277 .decl = decl,
3278 .fwd_decl = fwd_decl.toManaged(gpa),3278 .fwd_decl = fwd_decl.toManaged(gpa),
3279 .ctypes = .{},3279 .ctypes = .{},
src/codegen/c.zig+723-496
...@@ -31,6 +31,7 @@ pub const CType = @import("c/type.zig").CType;...@@ -31,6 +31,7 @@ pub const CType = @import("c/type.zig").CType;
3131
32pub const CValue = union(enum) {32pub const CValue = union(enum) {
33 none: void,33 none: void,
34 new_local: LocalIndex,
34 local: LocalIndex,35 local: LocalIndex,
35 /// Address of a local.36 /// Address of a local.
36 local_ref: LocalIndex,37 local_ref: LocalIndex,
...@@ -38,6 +39,8 @@ pub const CValue = union(enum) {...@@ -38,6 +39,8 @@ pub const CValue = union(enum) {
38 constant: Air.Inst.Ref,39 constant: Air.Inst.Ref,
39 /// Index into the parameters40 /// Index into the parameters
40 arg: usize,41 arg: usize,
42 /// The payload field of a parameter
43 arg_array: usize,
41 /// Index into a tuple's fields44 /// Index into a tuple's fields
42 field: usize,45 field: usize,
43 /// By-value46 /// By-value
...@@ -298,7 +301,7 @@ pub const Function = struct {...@@ -298,7 +301,7 @@ pub const Function = struct {
298 const alignment = 0;301 const alignment = 0;
299 const decl_c_value = try f.allocLocalValue(ty, alignment);302 const decl_c_value = try f.allocLocalValue(ty, alignment);
300 const gpa = f.object.dg.gpa;303 const gpa = f.object.dg.gpa;
301 try f.allocs.put(gpa, decl_c_value.local, true);304 try f.allocs.put(gpa, decl_c_value.new_local, true);
302 try writer.writeAll("static ");305 try writer.writeAll("static ");
303 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);306 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);
304 try writer.writeAll(" = ");307 try writer.writeAll(" = ");
...@@ -330,12 +333,12 @@ pub const Function = struct {...@@ -330,12 +333,12 @@ pub const Function = struct {
330 .alignment = alignment,333 .alignment = alignment,
331 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),334 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),
332 });335 });
333 return CValue{ .local = @intCast(LocalIndex, f.locals.items.len - 1) };336 return CValue{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
334 }337 }
335338
336 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {339 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
337 const result = try f.allocAlignedLocal(ty, .mut, 0);340 const result = try f.allocAlignedLocal(ty, .mut, 0);
338 log.debug("%{d}: allocating t{d}", .{ inst, result.local });341 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
339 return result;342 return result;
340 }343 }
341344
...@@ -349,7 +352,7 @@ pub const Function = struct {...@@ -349,7 +352,7 @@ pub const Function = struct {
349 if (local.alignment >= alignment) {352 if (local.alignment >= alignment) {
350 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);353 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
351 _ = locals_list.swapRemove(i);354 _ = locals_list.swapRemove(i);
352 return CValue{ .local = local_index };355 return CValue{ .new_local = local_index };
353 }356 }
354 }357 }
355 }358 }
...@@ -488,8 +491,8 @@ pub const Object = struct {...@@ -488,8 +491,8 @@ pub const Object = struct {
488pub const DeclGen = struct {491pub const DeclGen = struct {
489 gpa: std.mem.Allocator,492 gpa: std.mem.Allocator,
490 module: *Module,493 module: *Module,
491 decl: *Decl,494 decl: ?*Decl,
492 decl_index: Decl.Index,495 decl_index: Decl.OptionalIndex,
493 fwd_decl: std.ArrayList(u8),496 fwd_decl: std.ArrayList(u8),
494 error_msg: ?*Module.ErrorMsg,497 error_msg: ?*Module.ErrorMsg,
495 ctypes: CType.Store,498 ctypes: CType.Store,
...@@ -497,7 +500,7 @@ pub const DeclGen = struct {...@@ -497,7 +500,7 @@ pub const DeclGen = struct {
497 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {500 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
498 @setCold(true);501 @setCold(true);
499 const src = LazySrcLoc.nodeOffset(0);502 const src = LazySrcLoc.nodeOffset(0);
500 const src_loc = src.toSrcLoc(dg.decl);503 const src_loc = src.toSrcLoc(dg.decl.?);
501 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);504 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
502 return error.AnalysisFail;505 return error.AnalysisFail;
503 }506 }
...@@ -816,7 +819,7 @@ pub const DeclGen = struct {...@@ -816,7 +819,7 @@ pub const DeclGen = struct {
816819
817 empty = false;820 empty = false;
818 }821 }
819 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});822
820 return writer.writeByte('}');823 return writer.writeByte('}');
821 },824 },
822 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),825 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
...@@ -1287,7 +1290,6 @@ pub const DeclGen = struct {...@@ -1287,7 +1290,6 @@ pub const DeclGen = struct {
12871290
1288 empty = false;1291 empty = false;
1289 }1292 }
1290 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
1291 try writer.writeByte('}');1293 try writer.writeByte('}');
1292 },1294 },
1293 .Packed => {1295 .Packed => {
...@@ -1304,7 +1306,7 @@ pub const DeclGen = struct {...@@ -1304,7 +1306,7 @@ pub const DeclGen = struct {
1304 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);1306 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
13051307
1306 var eff_num_fields: usize = 0;1308 var eff_num_fields: usize = 0;
1307 for (field_vals, 0..) |_, index| {1309 for (0..field_vals.len) |index| {
1308 const field_ty = ty.structFieldType(index);1310 const field_ty = ty.structFieldType(index);
1309 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;1311 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
13101312
...@@ -1408,6 +1410,7 @@ pub const DeclGen = struct {...@@ -1408,6 +1410,7 @@ pub const DeclGen = struct {
1408 return;1410 return;
1409 }1411 }
14101412
1413 var has_payload_init = false;
1411 try writer.writeByte('{');1414 try writer.writeByte('{');
1412 if (ty.unionTagTypeSafety()) |tag_ty| {1415 if (ty.unionTagTypeSafety()) |tag_ty| {
1413 const layout = ty.unionGetLayout(target);1416 const layout = ty.unionGetLayout(target);
...@@ -1416,7 +1419,10 @@ pub const DeclGen = struct {...@@ -1416,7 +1419,10 @@ pub const DeclGen = struct {
1416 try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);1419 try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);
1417 try writer.writeAll(", ");1420 try writer.writeAll(", ");
1418 }1421 }
1419 try writer.writeAll(".payload = {");1422 if (!ty.unionHasAllZeroBitFieldTypes()) {
1423 try writer.writeAll(".payload = {");
1424 has_payload_init = true;
1425 }
1420 }1426 }
14211427
1422 var it = ty.unionFields().iterator();1428 var it = ty.unionFields().iterator();
...@@ -1428,8 +1434,8 @@ pub const DeclGen = struct {...@@ -1428,8 +1434,8 @@ pub const DeclGen = struct {
1428 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});1434 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});
1429 try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);1435 try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);
1430 break;1436 break;
1431 } else try writer.writeAll(".empty_union = 0");1437 }
1432 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');1438 if (has_payload_init) try writer.writeByte('}');
1433 try writer.writeByte('}');1439 try writer.writeByte('}');
1434 },1440 },
14351441
...@@ -1452,337 +1458,61 @@ pub const DeclGen = struct {...@@ -1452,337 +1458,61 @@ pub const DeclGen = struct {
1452 }1458 }
14531459
1454 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {1460 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {
1455 const fn_info = dg.decl.ty.fnInfo();1461 const store = &dg.ctypes.set;
1462 const module = dg.module;
1463
1464 const fn_ty = dg.decl.?.ty;
1465 const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) {
1466 .Forward => .forward,
1467 .Complete => .complete,
1468 });
1469
1470 const fn_info = fn_ty.fnInfo();
1456 if (fn_info.cc == .Naked) {1471 if (fn_info.cc == .Naked) {
1457 switch (kind) {1472 switch (kind) {
1458 .Forward => try w.writeAll("zig_naked_decl "),1473 .Forward => try w.writeAll("zig_naked_decl "),
1459 .Complete => try w.writeAll("zig_naked "),1474 .Complete => try w.writeAll("zig_naked "),
1460 }1475 }
1461 }1476 }
1462 if (dg.decl.val.castTag(.function)) |func_payload|1477 if (dg.decl.?.val.castTag(.function)) |func_payload|
1463 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");1478 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
14641479
1465 const target = dg.module.getTarget();1480 const trailing = try renderTypePrefix(
1466 var ret_buf: LowerFnRetTyBuffer = undefined;1481 dg.decl_index,
1467 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);1482 store.*,
14681483 module,
1469 try dg.renderType(w, ret_ty, kind);1484 w,
1470 try w.writeByte(' ');1485 fn_cty_idx,
1486 .suffix,
1487 CQualifiers.init(.{}),
1488 );
1489 try w.print("{}", .{trailing});
14711490
1472 if (toCallingConvention(fn_info.cc)) |call_conv| {1491 if (toCallingConvention(fn_info.cc)) |call_conv| {
1473 try w.print("zig_callconv({s}) ", .{call_conv});1492 try w.print("zig_callconv({s}) ", .{call_conv});
1474 }1493 }
14751494
1476 if (fn_info.alignment > 0 and kind == .Complete) try w.print(" zig_align_fn({})", .{fn_info.alignment});1495 if (fn_info.alignment > 0 and kind == .Complete) {
1496 try w.print(" zig_align_fn({})", .{fn_info.alignment});
1497 }
14771498
1478 try dg.renderDeclName(w, dg.decl_index, export_index);1499 try dg.renderDeclName(w, dg.decl_index.unwrap().?, export_index);
1479 try w.writeByte('(');
14801500
1481 var index: usize = 0;1501 try renderTypeSuffix(dg.decl_index, store.*, module, w, fn_cty_idx, .suffix);
1482 for (fn_info.param_types) |param_type| {
1483 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1484 if (index > 0) try w.writeAll(", ");
1485 const name = CValue{ .arg = index };
1486 try dg.renderTypeAndName(w, param_type, name, .@"const", 0, kind);
1487 index += 1;
1488 }
14891502
1490 if (fn_info.is_var_args) {1503 if (fn_info.alignment > 0 and kind == .Forward) {
1491 if (index > 0) try w.writeAll(", ");1504 try w.print(" zig_align_fn({})", .{fn_info.alignment});
1492 try w.writeAll("...");
1493 } else if (index == 0) {
1494 try dg.renderType(w, Type.void, kind);
1495 }1505 }
1496 try w.writeByte(')');
1497 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1498 }1506 }
14991507
1500 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {1508 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1501 return dg.ctypes.indexToCType(idx);1509 return dg.ctypes.indexToCType(idx);
1502 }1510 }
1503 fn typeToCType(dg: *DeclGen, ty: Type) !CType {1511 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
1504 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module);1512 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
1505 }
1506 fn typeToIndex(dg: *DeclGen, ty: Type) !CType.Index {
1507 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module);
1508 }
1509
1510 const CTypeFix = enum { prefix, suffix };
1511 const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1512 const CTypeRenderTrailing = enum {
1513 no_space,
1514 maybe_space,
1515
1516 pub fn format(
1517 self: @This(),
1518 comptime fmt: []const u8,
1519 _: std.fmt.FormatOptions,
1520 w: anytype,
1521 ) @TypeOf(w).Error!void {
1522 if (fmt.len != 0)
1523 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1524 @typeName(@This()) ++ "'");
1525 comptime assert(fmt.len == 0);
1526 switch (self) {
1527 .no_space => {},
1528 .maybe_space => try w.writeByte(' '),
1529 }
1530 }
1531 };
1532 fn renderTypePrefix(
1533 dg: *DeclGen,
1534 w: anytype,
1535 idx: CType.Index,
1536 parent_fix: CTypeFix,
1537 qualifiers: CQualifiers,
1538 ) @TypeOf(w).Error!CTypeRenderTrailing {
1539 var trailing = CTypeRenderTrailing.maybe_space;
1540
1541 const cty = dg.indexToCType(idx);
1542 switch (cty.tag()) {
1543 .void,
1544 .char,
1545 .@"signed char",
1546 .short,
1547 .int,
1548 .long,
1549 .@"long long",
1550 ._Bool,
1551 .@"unsigned char",
1552 .@"unsigned short",
1553 .@"unsigned int",
1554 .@"unsigned long",
1555 .@"unsigned long long",
1556 .float,
1557 .double,
1558 .@"long double",
1559 .bool,
1560 .size_t,
1561 .ptrdiff_t,
1562 .uint8_t,
1563 .int8_t,
1564 .uint16_t,
1565 .int16_t,
1566 .uint32_t,
1567 .int32_t,
1568 .uint64_t,
1569 .int64_t,
1570 .uintptr_t,
1571 .intptr_t,
1572 .zig_u128,
1573 .zig_i128,
1574 .zig_f16,
1575 .zig_f32,
1576 .zig_f64,
1577 .zig_f80,
1578 .zig_f128,
1579 => |tag| try w.writeAll(@tagName(tag)),
1580
1581 .pointer,
1582 .pointer_const,
1583 .pointer_volatile,
1584 .pointer_const_volatile,
1585 => |tag| {
1586 const child_idx = cty.cast(CType.Payload.Child).?.data;
1587 try w.print("{}*", .{try dg.renderTypePrefix(w, child_idx, .prefix, CQualifiers.init(.{
1588 .@"const" = switch (tag) {
1589 .pointer, .pointer_volatile => false,
1590 .pointer_const, .pointer_const_volatile => true,
1591 else => unreachable,
1592 },
1593 .@"volatile" = switch (tag) {
1594 .pointer, .pointer_const => false,
1595 .pointer_volatile, .pointer_const_volatile => true,
1596 else => unreachable,
1597 },
1598 }))});
1599 trailing = .no_space;
1600 },
1601
1602 .array,
1603 .vector,
1604 => {
1605 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
1606 const child_trailing = try dg.renderTypePrefix(w, child_idx, .suffix, qualifiers);
1607 switch (parent_fix) {
1608 .prefix => {
1609 try w.print("{}(", .{child_trailing});
1610 return .no_space;
1611 },
1612 .suffix => return child_trailing,
1613 }
1614 },
1615
1616 .fwd_struct,
1617 .fwd_union,
1618 .anon_struct,
1619 .packed_anon_struct,
1620 => |tag| try w.print("{s} {}__{d}", .{
1621 switch (tag) {
1622 .fwd_struct,
1623 .anon_struct,
1624 .packed_anon_struct,
1625 => "struct",
1626 .fwd_union => "union",
1627 else => unreachable,
1628 },
1629 fmtIdent(switch (tag) {
1630 .fwd_struct,
1631 .fwd_union,
1632 => mem.span(dg.module.declPtr(cty.cast(CType.Payload.FwdDecl).?.data).name),
1633 .anon_struct,
1634 .packed_anon_struct,
1635 => "anon",
1636 else => unreachable,
1637 }),
1638 idx,
1639 }),
1640
1641 .@"struct",
1642 .packed_struct,
1643 .@"union",
1644 .packed_union,
1645 => return dg.renderTypePrefix(
1646 w,
1647 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
1648 parent_fix,
1649 qualifiers,
1650 ),
1651
1652 .function,
1653 .varargs_function,
1654 => {
1655 const child_trailing = try dg.renderTypePrefix(
1656 w,
1657 cty.cast(CType.Payload.Function).?.data.return_type,
1658 .suffix,
1659 CQualifiers.initEmpty(),
1660 );
1661 switch (parent_fix) {
1662 .prefix => {
1663 try w.print("{}(", .{child_trailing});
1664 return .no_space;
1665 },
1666 .suffix => return child_trailing,
1667 }
1668 },
1669 }
1670
1671 var qualifier_it = qualifiers.iterator();
1672 while (qualifier_it.next()) |qualifier| {
1673 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
1674 trailing = .maybe_space;
1675 }
1676
1677 return trailing;
1678 }1513 }
1679 fn renderTypeSuffix(1514 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1680 dg: *DeclGen,1515 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
1681 w: anytype,
1682 idx: CType.Index,
1683 parent_fix: CTypeFix,
1684 ) @TypeOf(w).Error!void {
1685 const cty = dg.indexToCType(idx);
1686 switch (cty.tag()) {
1687 .void,
1688 .char,
1689 .@"signed char",
1690 .short,
1691 .int,
1692 .long,
1693 .@"long long",
1694 ._Bool,
1695 .@"unsigned char",
1696 .@"unsigned short",
1697 .@"unsigned int",
1698 .@"unsigned long",
1699 .@"unsigned long long",
1700 .float,
1701 .double,
1702 .@"long double",
1703 .bool,
1704 .size_t,
1705 .ptrdiff_t,
1706 .uint8_t,
1707 .int8_t,
1708 .uint16_t,
1709 .int16_t,
1710 .uint32_t,
1711 .int32_t,
1712 .uint64_t,
1713 .int64_t,
1714 .uintptr_t,
1715 .intptr_t,
1716 .zig_u128,
1717 .zig_i128,
1718 .zig_f16,
1719 .zig_f32,
1720 .zig_f64,
1721 .zig_f80,
1722 .zig_f128,
1723 => {},
1724
1725 .pointer,
1726 .pointer_const,
1727 .pointer_volatile,
1728 .pointer_const_volatile,
1729 => try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Child).?.data, .prefix),
1730
1731 .array,
1732 .vector,
1733 => {
1734 switch (parent_fix) {
1735 .prefix => try w.writeByte(')'),
1736 .suffix => {},
1737 }
1738
1739 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
1740 try dg.renderTypeSuffix(w, cty.cast(CType.Payload.Sequence).?.data.elem_type, .suffix);
1741 },
1742
1743 .fwd_struct,
1744 .fwd_union,
1745 .anon_struct,
1746 .packed_anon_struct,
1747 .@"struct",
1748 .@"union",
1749 .packed_struct,
1750 .packed_union,
1751 => {},
1752
1753 .function,
1754 .varargs_function,
1755 => |tag| {
1756 switch (parent_fix) {
1757 .prefix => try w.writeByte(')'),
1758 .suffix => {},
1759 }
1760
1761 const data = cty.cast(CType.Payload.Function).?.data;
1762
1763 try w.writeByte('(');
1764 var need_comma = false;
1765 for (data.param_types) |param_type| {
1766 if (need_comma) try w.writeAll(", ");
1767 need_comma = true;
1768 _ = try dg.renderTypePrefix(w, param_type, .suffix, CQualifiers.initEmpty());
1769 try dg.renderTypeSuffix(w, param_type, .suffix);
1770 }
1771 switch (tag) {
1772 .function => {},
1773 .varargs_function => {
1774 if (need_comma) try w.writeAll(", ");
1775 need_comma = true;
1776 try w.writeAll("...");
1777 },
1778 else => unreachable,
1779 }
1780 if (!need_comma) try w.writeAll("void");
1781 try w.writeByte(')');
1782
1783 try dg.renderTypeSuffix(w, data.return_type, .suffix);
1784 },
1785 }
1786 }1516 }
17871517
1788 /// Renders a type as a single identifier, generating intermediate typedefs1518 /// Renders a type as a single identifier, generating intermediate typedefs
...@@ -1803,9 +1533,19 @@ pub const DeclGen = struct {...@@ -1803,9 +1533,19 @@ pub const DeclGen = struct {
1803 t: Type,1533 t: Type,
1804 _: TypedefKind,1534 _: TypedefKind,
1805 ) error{ OutOfMemory, AnalysisFail }!void {1535 ) error{ OutOfMemory, AnalysisFail }!void {
1806 const idx = try dg.typeToIndex(t);1536 const store = &dg.ctypes.set;
1807 _ = try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.initEmpty());1537 const module = dg.module;
1808 try dg.renderTypeSuffix(w, idx, .suffix);1538 const idx = try dg.typeToIndex(t, .complete);
1539 _ = try renderTypePrefix(
1540 dg.decl_index,
1541 store.*,
1542 module,
1543 w,
1544 idx,
1545 .suffix,
1546 CQualifiers.init(.{}),
1547 );
1548 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
1809 }1549 }
18101550
1811 const IntCastContext = union(enum) {1551 const IntCastContext = union(enum) {
...@@ -1939,24 +1679,28 @@ pub const DeclGen = struct {...@@ -1939,24 +1679,28 @@ pub const DeclGen = struct {
1939 alignment: u32,1679 alignment: u32,
1940 _: TypedefKind,1680 _: TypedefKind,
1941 ) error{ OutOfMemory, AnalysisFail }!void {1681 ) error{ OutOfMemory, AnalysisFail }!void {
1942 if (alignment != 0) {1682 const store = &dg.ctypes.set;
1943 const abi_alignment = ty.abiAlignment(dg.module.getTarget());1683 const module = dg.module;
1944 if (alignment < abi_alignment) {
1945 try w.print("zig_under_align({}) ", .{alignment});
1946 } else if (alignment > abi_alignment) {
1947 try w.print("zig_align({}) ", .{alignment});
1948 }
1949 }
19501684
1951 const idx = try dg.typeToIndex(ty);1685 if (alignment != 0) switch (std.math.order(alignment, ty.abiAlignment(dg.module.getTarget()))) {
1952 try w.print("{}", .{try dg.renderTypePrefix(w, idx, .suffix, CQualifiers.init(.{1686 .lt => try w.print("zig_under_align({}) ", .{alignment}),
1953 .@"const" = switch (mutability) {1687 .eq => {},
1954 .mut => false,1688 .gt => try w.print("zig_align({}) ", .{alignment}),
1955 .@"const" => true,1689 };
1956 },1690
1957 }))});1691 const idx = try dg.typeToIndex(ty, .complete);
1692 const trailing = try renderTypePrefix(
1693 dg.decl_index,
1694 store.*,
1695 module,
1696 w,
1697 idx,
1698 .suffix,
1699 CQualifiers.init(.{ .@"const" = mutability == .@"const" }),
1700 );
1701 try w.print("{}", .{trailing});
1958 try dg.writeCValue(w, name);1702 try dg.writeCValue(w, name);
1959 try dg.renderTypeSuffix(w, idx, .suffix);1703 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
1960 }1704 }
19611705
1962 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {1706 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
...@@ -2029,10 +1773,11 @@ pub const DeclGen = struct {...@@ -2029,10 +1773,11 @@ pub const DeclGen = struct {
2029 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {1773 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2030 switch (c_value) {1774 switch (c_value) {
2031 .none => unreachable,1775 .none => unreachable,
2032 .local => |i| return w.print("t{d}", .{i}),1776 .local, .new_local => |i| return w.print("t{d}", .{i}),
2033 .local_ref => |i| return w.print("&t{d}", .{i}),1777 .local_ref => |i| return w.print("&t{d}", .{i}),
2034 .constant => unreachable,1778 .constant => unreachable,
2035 .arg => |i| return w.print("a{d}", .{i}),1779 .arg => |i| return w.print("a{d}", .{i}),
1780 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
2036 .field => |i| return w.print("f{d}", .{i}),1781 .field => |i| return w.print("f{d}", .{i}),
2037 .decl => |decl| return dg.renderDeclName(w, decl, 0),1782 .decl => |decl| return dg.renderDeclName(w, decl, 0),
2038 .decl_ref => |decl| {1783 .decl_ref => |decl| {
...@@ -2048,10 +1793,15 @@ pub const DeclGen = struct {...@@ -2048,10 +1793,15 @@ pub const DeclGen = struct {
2048 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {1793 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2049 switch (c_value) {1794 switch (c_value) {
2050 .none => unreachable,1795 .none => unreachable,
2051 .local => |i| return w.print("(*t{d})", .{i}),1796 .local, .new_local => |i| return w.print("(*t{d})", .{i}),
2052 .local_ref => |i| return w.print("t{d}", .{i}),1797 .local_ref => |i| return w.print("t{d}", .{i}),
2053 .constant => unreachable,1798 .constant => unreachable,
2054 .arg => |i| return w.print("(*a{d})", .{i}),1799 .arg => |i| return w.print("(*a{d})", .{i}),
1800 .arg_array => |i| {
1801 try w.writeAll("(*");
1802 try dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" });
1803 return w.writeByte(')');
1804 },
2055 .field => |i| return w.print("f{d}", .{i}),1805 .field => |i| return w.print("f{d}", .{i}),
2056 .decl => |decl| {1806 .decl => |decl| {
2057 try w.writeAll("(*");1807 try w.writeAll("(*");
...@@ -2078,7 +1828,7 @@ pub const DeclGen = struct {...@@ -2078,7 +1828,7 @@ pub const DeclGen = struct {
2078 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {1828 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
2079 switch (c_value) {1829 switch (c_value) {
2080 .none, .constant, .field, .undef => unreachable,1830 .none, .constant, .field, .undef => unreachable,
2081 .local, .arg, .decl, .identifier, .bytes => {1831 .new_local, .local, .arg, .arg_array, .decl, .identifier, .bytes => {
2082 try dg.writeCValue(writer, c_value);1832 try dg.writeCValue(writer, c_value);
2083 try writer.writeAll("->");1833 try writer.writeAll("->");
2084 },1834 },
...@@ -2205,10 +1955,491 @@ pub const DeclGen = struct {...@@ -2205,10 +1955,491 @@ pub const DeclGen = struct {
2205 }1955 }
2206};1956};
22071957
2208pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {1958const CTypeFix = enum { prefix, suffix };
1959const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1960const CTypeRenderTrailing = enum {
1961 no_space,
1962 maybe_space,
1963
1964 pub fn format(
1965 self: @This(),
1966 comptime fmt: []const u8,
1967 _: std.fmt.FormatOptions,
1968 w: anytype,
1969 ) @TypeOf(w).Error!void {
1970 if (fmt.len != 0)
1971 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1972 @typeName(@This()) ++ "'");
1973 comptime assert(fmt.len == 0);
1974 switch (self) {
1975 .no_space => {},
1976 .maybe_space => try w.writeByte(' '),
1977 }
1978 }
1979};
1980fn renderTypeName(
1981 mod: *Module,
1982 w: anytype,
1983 idx: CType.Index,
1984 cty: CType,
1985 attributes: []const u8,
1986) !void {
1987 switch (cty.tag()) {
1988 else => unreachable,
1989
1990 .fwd_anon_struct,
1991 .fwd_anon_union,
1992 => |tag| try w.print("{s} {s}anon__lazy_{d}", .{
1993 @tagName(tag)["fwd_anon_".len..],
1994 attributes,
1995 idx,
1996 }),
1997
1998 .fwd_struct,
1999 .fwd_union,
2000 => |tag| {
2001 const owner_decl = cty.cast(CType.Payload.FwdDecl).?.data;
2002 try w.print("{s} {s}{}__{d}", .{
2003 @tagName(tag)["fwd_".len..],
2004 attributes,
2005 fmtIdent(mem.span(mod.declPtr(owner_decl).name)),
2006 @enumToInt(owner_decl),
2007 });
2008 },
2009 }
2010}
2011fn renderTypePrefix(
2012 decl: Decl.OptionalIndex,
2013 store: CType.Store.Set,
2014 mod: *Module,
2015 w: anytype,
2016 idx: CType.Index,
2017 parent_fix: CTypeFix,
2018 qualifiers: CQualifiers,
2019) @TypeOf(w).Error!CTypeRenderTrailing {
2020 var trailing = CTypeRenderTrailing.maybe_space;
2021
2022 const cty = store.indexToCType(idx);
2023 switch (cty.tag()) {
2024 .void,
2025 .char,
2026 .@"signed char",
2027 .short,
2028 .int,
2029 .long,
2030 .@"long long",
2031 ._Bool,
2032 .@"unsigned char",
2033 .@"unsigned short",
2034 .@"unsigned int",
2035 .@"unsigned long",
2036 .@"unsigned long long",
2037 .float,
2038 .double,
2039 .@"long double",
2040 .bool,
2041 .size_t,
2042 .ptrdiff_t,
2043 .uint8_t,
2044 .int8_t,
2045 .uint16_t,
2046 .int16_t,
2047 .uint32_t,
2048 .int32_t,
2049 .uint64_t,
2050 .int64_t,
2051 .uintptr_t,
2052 .intptr_t,
2053 .zig_u128,
2054 .zig_i128,
2055 .zig_f16,
2056 .zig_f32,
2057 .zig_f64,
2058 .zig_f80,
2059 .zig_f128,
2060 => |tag| try w.writeAll(@tagName(tag)),
2061
2062 .pointer,
2063 .pointer_const,
2064 .pointer_volatile,
2065 .pointer_const_volatile,
2066 => |tag| {
2067 const child_idx = cty.cast(CType.Payload.Child).?.data;
2068 const child_trailing = try renderTypePrefix(
2069 decl,
2070 store,
2071 mod,
2072 w,
2073 child_idx,
2074 .prefix,
2075 CQualifiers.init(.{ .@"const" = switch (tag) {
2076 .pointer, .pointer_volatile => false,
2077 .pointer_const, .pointer_const_volatile => true,
2078 else => unreachable,
2079 }, .@"volatile" = switch (tag) {
2080 .pointer, .pointer_const => false,
2081 .pointer_volatile, .pointer_const_volatile => true,
2082 else => unreachable,
2083 } }),
2084 );
2085 try w.print("{}*", .{child_trailing});
2086 trailing = .no_space;
2087 },
2088
2089 .array,
2090 .vector,
2091 => {
2092 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
2093 const child_trailing = try renderTypePrefix(
2094 decl,
2095 store,
2096 mod,
2097 w,
2098 child_idx,
2099 .suffix,
2100 qualifiers,
2101 );
2102 switch (parent_fix) {
2103 .prefix => {
2104 try w.print("{}(", .{child_trailing});
2105 return .no_space;
2106 },
2107 .suffix => return child_trailing,
2108 }
2109 },
2110
2111 .fwd_anon_struct,
2112 .fwd_anon_union,
2113 => if (decl.unwrap()) |decl_index|
2114 try w.print("anon__{d}_{d}", .{ @enumToInt(decl_index), idx })
2115 else
2116 try renderTypeName(mod, w, idx, cty, ""),
2117
2118 .fwd_struct,
2119 .fwd_union,
2120 => try renderTypeName(mod, w, idx, cty, ""),
2121
2122 .unnamed_struct,
2123 .unnamed_union,
2124 .packed_unnamed_struct,
2125 .packed_unnamed_union,
2126 => |tag| {
2127 try w.print("{s} {s}", .{
2128 @tagName(tag)["unnamed_".len..],
2129 if (cty.isPacked()) "zig_packed(" else "",
2130 });
2131 try renderAggregateFields(mod, w, store, cty, 1);
2132 if (cty.isPacked()) try w.writeByte(')');
2133 },
2134
2135 .anon_struct,
2136 .anon_union,
2137 .@"struct",
2138 .@"union",
2139 .packed_struct,
2140 .packed_union,
2141 => return renderTypePrefix(
2142 decl,
2143 store,
2144 mod,
2145 w,
2146 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
2147 parent_fix,
2148 qualifiers,
2149 ),
2150
2151 .function,
2152 .varargs_function,
2153 => {
2154 const child_trailing = try renderTypePrefix(
2155 decl,
2156 store,
2157 mod,
2158 w,
2159 cty.cast(CType.Payload.Function).?.data.return_type,
2160 .suffix,
2161 CQualifiers.init(.{}),
2162 );
2163 switch (parent_fix) {
2164 .prefix => {
2165 try w.print("{}(", .{child_trailing});
2166 return .no_space;
2167 },
2168 .suffix => return child_trailing,
2169 }
2170 },
2171 }
2172
2173 var qualifier_it = qualifiers.iterator();
2174 while (qualifier_it.next()) |qualifier| {
2175 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2176 trailing = .maybe_space;
2177 }
2178
2179 return trailing;
2180}
2181fn renderTypeSuffix(
2182 decl: Decl.OptionalIndex,
2183 store: CType.Store.Set,
2184 mod: *Module,
2185 w: anytype,
2186 idx: CType.Index,
2187 parent_fix: CTypeFix,
2188) @TypeOf(w).Error!void {
2189 const cty = store.indexToCType(idx);
2190 switch (cty.tag()) {
2191 .void,
2192 .char,
2193 .@"signed char",
2194 .short,
2195 .int,
2196 .long,
2197 .@"long long",
2198 ._Bool,
2199 .@"unsigned char",
2200 .@"unsigned short",
2201 .@"unsigned int",
2202 .@"unsigned long",
2203 .@"unsigned long long",
2204 .float,
2205 .double,
2206 .@"long double",
2207 .bool,
2208 .size_t,
2209 .ptrdiff_t,
2210 .uint8_t,
2211 .int8_t,
2212 .uint16_t,
2213 .int16_t,
2214 .uint32_t,
2215 .int32_t,
2216 .uint64_t,
2217 .int64_t,
2218 .uintptr_t,
2219 .intptr_t,
2220 .zig_u128,
2221 .zig_i128,
2222 .zig_f16,
2223 .zig_f32,
2224 .zig_f64,
2225 .zig_f80,
2226 .zig_f128,
2227 => {},
2228
2229 .pointer,
2230 .pointer_const,
2231 .pointer_volatile,
2232 .pointer_const_volatile,
2233 => try renderTypeSuffix(decl, store, mod, w, cty.cast(CType.Payload.Child).?.data, .prefix),
2234
2235 .array,
2236 .vector,
2237 => {
2238 switch (parent_fix) {
2239 .prefix => try w.writeByte(')'),
2240 .suffix => {},
2241 }
2242
2243 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
2244 try renderTypeSuffix(
2245 decl,
2246 store,
2247 mod,
2248 w,
2249 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2250 .suffix,
2251 );
2252 },
2253
2254 .fwd_anon_struct,
2255 .fwd_anon_union,
2256 .fwd_struct,
2257 .fwd_union,
2258 .unnamed_struct,
2259 .unnamed_union,
2260 .packed_unnamed_struct,
2261 .packed_unnamed_union,
2262 .anon_struct,
2263 .anon_union,
2264 .@"struct",
2265 .@"union",
2266 .packed_struct,
2267 .packed_union,
2268 => {},
2269
2270 .function,
2271 .varargs_function,
2272 => |tag| {
2273 switch (parent_fix) {
2274 .prefix => try w.writeByte(')'),
2275 .suffix => {},
2276 }
2277
2278 const data = cty.cast(CType.Payload.Function).?.data;
2279
2280 try w.writeByte('(');
2281 var need_comma = false;
2282 for (data.param_types, 0..) |param_type, param_i| {
2283 if (need_comma) try w.writeAll(", ");
2284 need_comma = true;
2285 const trailing = try renderTypePrefix(
2286 decl,
2287 store,
2288 mod,
2289 w,
2290 param_type,
2291 .suffix,
2292 CQualifiers.init(.{}),
2293 );
2294 try w.print("{}a{d}", .{ trailing, param_i });
2295 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix);
2296 }
2297 switch (tag) {
2298 .function => {},
2299 .varargs_function => {
2300 if (need_comma) try w.writeAll(", ");
2301 need_comma = true;
2302 try w.writeAll("...");
2303 },
2304 else => unreachable,
2305 }
2306 if (!need_comma) try w.writeAll("void");
2307 try w.writeByte(')');
2308
2309 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix);
2310 },
2311 }
2312}
2313fn renderAggregateFields(
2314 mod: *Module,
2315 writer: anytype,
2316 store: CType.Store.Set,
2317 cty: CType,
2318 indent: usize,
2319) !void {
2320 try writer.writeAll("{\n");
2321 const fields = cty.fields();
2322 for (fields) |field| {
2323 try writer.writeByteNTimes(' ', indent + 1);
2324 switch (std.math.order(field.alignas.@"align", field.alignas.abi)) {
2325 .lt => try writer.print("zig_under_align({}) ", .{field.alignas.getAlign()}),
2326 .eq => {},
2327 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
2328 }
2329 const trailing = try renderTypePrefix(
2330 .none,
2331 store,
2332 mod,
2333 writer,
2334 field.type,
2335 .suffix,
2336 CQualifiers.init(.{}),
2337 );
2338 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2339 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix);
2340 try writer.writeAll(";\n");
2341 }
2342 try writer.writeByteNTimes(' ', indent);
2343 try writer.writeByte('}');
2344}
2345
2346pub fn genTypeDecl(
2347 mod: *Module,
2348 writer: anytype,
2349 global_store: CType.Store.Set,
2350 global_idx: CType.Index,
2351 decl: Decl.OptionalIndex,
2352 decl_store: CType.Store.Set,
2353 decl_idx: CType.Index,
2354 found_existing: bool,
2355) !void {
2356 const global_cty = global_store.indexToCType(global_idx);
2357 switch (global_cty.tag()) {
2358 .fwd_anon_struct => if (decl != .none) {
2359 try writer.writeAll("typedef ");
2360 _ = try renderTypePrefix(
2361 .none,
2362 global_store,
2363 mod,
2364 writer,
2365 global_idx,
2366 .suffix,
2367 CQualifiers.init(.{}),
2368 );
2369 try writer.writeByte(' ');
2370 _ = try renderTypePrefix(
2371 decl,
2372 decl_store,
2373 mod,
2374 writer,
2375 decl_idx,
2376 .suffix,
2377 CQualifiers.init(.{}),
2378 );
2379 try writer.writeAll(";\n");
2380 },
2381
2382 .fwd_struct,
2383 .fwd_union,
2384 .anon_struct,
2385 .anon_union,
2386 .@"struct",
2387 .@"union",
2388 .packed_struct,
2389 .packed_union,
2390 => |tag| if (!found_existing) {
2391 switch (tag) {
2392 .fwd_struct,
2393 .fwd_union,
2394 => {
2395 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2396 _ = try renderTypePrefix(
2397 .none,
2398 global_store,
2399 mod,
2400 writer,
2401 global_idx,
2402 .suffix,
2403 CQualifiers.init(.{}),
2404 );
2405 try writer.writeAll("; // ");
2406 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
2407 try writer.writeByte('\n');
2408 },
2409
2410 .anon_struct,
2411 .anon_union,
2412 .@"struct",
2413 .@"union",
2414 .packed_struct,
2415 .packed_union,
2416 => {
2417 const fwd_idx = global_cty.cast(CType.Payload.Aggregate).?.data.fwd_decl;
2418 try renderTypeName(
2419 mod,
2420 writer,
2421 fwd_idx,
2422 global_store.indexToCType(fwd_idx),
2423 if (global_cty.isPacked()) "zig_packed(" else "",
2424 );
2425 try writer.writeByte(' ');
2426 try renderAggregateFields(mod, writer, global_store, global_cty, 0);
2427 if (global_cty.isPacked()) try writer.writeByte(')');
2428 try writer.writeAll(";\n");
2429 },
2430
2431 else => unreachable,
2432 }
2433 },
2434
2435 else => {},
2436 }
2437}
2438
2439pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
2209 var it = mod.global_assembly.valueIterator();2440 var it = mod.global_assembly.valueIterator();
2210 while (it.next()) |asm_source| {2441 while (it.next()) |asm_source| {
2211 try code.writer().print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});2442 try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
2212 }2443 }
2213}2444}
22142445
...@@ -2279,14 +2510,16 @@ fn genExports(o: *Object) !void {...@@ -2279,14 +2510,16 @@ fn genExports(o: *Object) !void {
2279 defer tracy.end();2510 defer tracy.end();
22802511
2281 const fwd_decl_writer = o.dg.fwd_decl.writer();2512 const fwd_decl_writer = o.dg.fwd_decl.writer();
2282 if (o.dg.module.decl_exports.get(o.dg.decl_index)) |exports| for (exports.items[1..], 0..) |@"export", i| {2513 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
2283 try fwd_decl_writer.writeAll("zig_export(");2514 for (exports.items[1..], 1..) |@"export", i| {
2284 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, 1 + i));2515 try fwd_decl_writer.writeAll("zig_export(");
2285 try fwd_decl_writer.print(", {s}, {s});\n", .{2516 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, i));
2286 fmtStringLiteral(exports.items[0].options.name),2517 try fwd_decl_writer.print(", {s}, {s});\n", .{
2287 fmtStringLiteral(@"export".options.name),2518 fmtStringLiteral(exports.items[0].options.name),
2288 });2519 fmtStringLiteral(@"export".options.name),
2289 };2520 });
2521 }
2522 }
2290}2523}
22912524
2292pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {2525pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
...@@ -2307,8 +2540,8 @@ pub fn genFunc(f: *Function) !void {...@@ -2307,8 +2540,8 @@ pub fn genFunc(f: *Function) !void {
2307 const o = &f.object;2540 const o = &f.object;
2308 const gpa = o.dg.gpa;2541 const gpa = o.dg.gpa;
2309 const tv: TypedValue = .{2542 const tv: TypedValue = .{
2310 .ty = o.dg.decl.ty,2543 .ty = o.dg.decl.?.ty,
2311 .val = o.dg.decl.val,2544 .val = o.dg.decl.?.val,
2312 };2545 };
23132546
2314 o.code_header = std.ArrayList(u8).init(gpa);2547 o.code_header = std.ArrayList(u8).init(gpa);
...@@ -2347,9 +2580,8 @@ pub fn genFunc(f: *Function) !void {...@@ -2347,9 +2580,8 @@ pub fn genFunc(f: *Function) !void {
2347 // missing. These are added now to complete the map. Then we can sort by2580 // missing. These are added now to complete the map. Then we can sort by
2348 // alignment, descending.2581 // alignment, descending.
2349 const free_locals = f.getFreeLocals();2582 const free_locals = f.getFreeLocals();
2350 const values = f.allocs.values();2583 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
2351 for (f.allocs.keys(), 0..) |local_index, i| {2584 if (value) continue; // static
2352 if (values[i]) continue; // static
2353 const local = f.locals.items[local_index];2585 const local = f.locals.items[local_index];
2354 log.debug("inserting local {d} into free_locals", .{local_index});2586 log.debug("inserting local {d} into free_locals", .{local_index});
2355 const gop = try free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx());2587 const gop = try free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx());
...@@ -2398,10 +2630,10 @@ pub fn genDecl(o: *Object) !void {...@@ -2398,10 +2630,10 @@ pub fn genDecl(o: *Object) !void {
2398 const tracy = trace(@src());2630 const tracy = trace(@src());
2399 defer tracy.end();2631 defer tracy.end();
24002632
2401 const tv: TypedValue = .{2633 const decl = o.dg.decl.?;
2402 .ty = o.dg.decl.ty,2634 const decl_c_value: CValue = .{ .decl = o.dg.decl_index.unwrap().? };
2403 .val = o.dg.decl.val,2635 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };
2404 };2636
2405 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;2637 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;
2406 if (tv.val.tag() == .extern_fn) {2638 if (tv.val.tag() == .extern_fn) {
2407 const fwd_decl_writer = o.dg.fwd_decl.writer();2639 const fwd_decl_writer = o.dg.fwd_decl.writer();
...@@ -2415,11 +2647,9 @@ pub fn genDecl(o: *Object) !void {...@@ -2415,11 +2647,9 @@ pub fn genDecl(o: *Object) !void {
2415 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;2647 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
2416 const fwd_decl_writer = o.dg.fwd_decl.writer();2648 const fwd_decl_writer = o.dg.fwd_decl.writer();
24172649
2418 const decl_c_value = CValue{ .decl = o.dg.decl_index };
2419
2420 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2650 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2421 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");2651 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2422 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);2652 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .mut, decl.@"align", .Complete);
2423 try fwd_decl_writer.writeAll(";\n");2653 try fwd_decl_writer.writeAll(";\n");
2424 try genExports(o);2654 try genExports(o);
24252655
...@@ -2428,27 +2658,26 @@ pub fn genDecl(o: *Object) !void {...@@ -2428,27 +2658,26 @@ pub fn genDecl(o: *Object) !void {
2428 const w = o.writer();2658 const w = o.writer();
2429 if (!is_global) try w.writeAll("static ");2659 if (!is_global) try w.writeAll("static ");
2430 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2660 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2431 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2661 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2432 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .mut, o.dg.decl.@"align", .Complete);2662 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .mut, decl.@"align", .Complete);
2433 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");2663 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
2434 try w.writeAll(" = ");2664 try w.writeAll(" = ");
2435 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);2665 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
2436 try w.writeByte(';');2666 try w.writeByte(';');
2437 try o.indent_writer.insertNewline();2667 try o.indent_writer.insertNewline();
2438 } else {2668 } else {
2439 const is_global = o.dg.module.decl_exports.contains(o.dg.decl_index);2669 const is_global = o.dg.module.decl_exports.contains(decl_c_value.decl);
2440 const fwd_decl_writer = o.dg.fwd_decl.writer();2670 const fwd_decl_writer = o.dg.fwd_decl.writer();
2441 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
24422671
2443 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2672 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2444 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);2673 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
2445 try fwd_decl_writer.writeAll(";\n");2674 try fwd_decl_writer.writeAll(";\n");
24462675
2447 const w = o.writer();2676 const w = o.writer();
2448 if (!is_global) try w.writeAll("static ");2677 if (!is_global) try w.writeAll("static ");
2449 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2678 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2450 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", o.dg.decl.@"align", .Complete);2679 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
2451 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");2680 if (decl.@"linksection" != null) try w.writeAll(", read)");
2452 try w.writeAll(" = ");2681 try w.writeAll(" = ");
2453 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2682 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
2454 try w.writeAll(";\n");2683 try w.writeAll(";\n");
...@@ -2460,8 +2689,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2460,8 +2689,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2460 defer tracy.end();2689 defer tracy.end();
24612690
2462 const tv: TypedValue = .{2691 const tv: TypedValue = .{
2463 .ty = dg.decl.ty,2692 .ty = dg.decl.?.ty,
2464 .val = dg.decl.val,2693 .val = dg.decl.?.val,
2465 };2694 };
2466 const writer = dg.fwd_decl.writer();2695 const writer = dg.fwd_decl.writer();
24672696
...@@ -2499,7 +2728,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2499,7 +2728,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2499 // zig fmt: off2728 // zig fmt: off
2500 .constant => unreachable, // excluded from function bodies2729 .constant => unreachable, // excluded from function bodies
2501 .const_ty => unreachable, // excluded from function bodies2730 .const_ty => unreachable, // excluded from function bodies
2502 .arg => airArg(f),2731 .arg => try airArg(f, inst),
25032732
2504 .breakpoint => try airBreakpoint(f.object.writer()),2733 .breakpoint => try airBreakpoint(f.object.writer()),
2505 .ret_addr => try airRetAddr(f, inst),2734 .ret_addr => try airRetAddr(f, inst),
...@@ -2748,13 +2977,14 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2748,13 +2977,14 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2748 .c_va_start => return f.fail("TODO implement c_va_start", .{}),2977 .c_va_start => return f.fail("TODO implement c_va_start", .{}),
2749 // zig fmt: on2978 // zig fmt: on
2750 };2979 };
2751 if (result_value == .local) {2980 if (result_value == .new_local) {
2752 log.debug("map %{d} to t{d}", .{ inst, result_value.local });2981 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });
2753 }
2754 switch (result_value) {
2755 .none => {},
2756 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),
2757 }2982 }
2983 try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) {
2984 .none => continue,
2985 .new_local => |i| .{ .local = i },
2986 else => result_value,
2987 });
2758 }2988 }
2759}2989}
27602990
...@@ -2979,10 +3209,10 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2979,10 +3209,10 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
2979 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;3209 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
2980 const target = f.object.dg.module.getTarget();3210 const target = f.object.dg.module.getTarget();
2981 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));3211 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
2982 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });3212 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
2983 const gpa = f.object.dg.module.gpa;3213 const gpa = f.object.dg.module.gpa;
2984 try f.allocs.put(gpa, local.local, false);3214 try f.allocs.put(gpa, local.new_local, false);
2985 return CValue{ .local_ref = local.local };3215 return CValue{ .local_ref = local.new_local };
2986}3216}
29873217
2988fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3218fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -2996,16 +3226,22 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2996,16 +3226,22 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2996 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;3226 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
2997 const target = f.object.dg.module.getTarget();3227 const target = f.object.dg.module.getTarget();
2998 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));3228 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
2999 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });3229 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3000 const gpa = f.object.dg.module.gpa;3230 const gpa = f.object.dg.module.gpa;
3001 try f.allocs.put(gpa, local.local, false);3231 try f.allocs.put(gpa, local.new_local, false);
3002 return CValue{ .local_ref = local.local };3232 return CValue{ .local_ref = local.new_local };
3003}3233}
30043234
3005fn airArg(f: *Function) CValue {3235fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
3236 const inst_ty = f.air.typeOfIndex(inst);
3237 const inst_cty = try f.object.dg.typeToIndex(inst_ty, .parameter);
3238
3006 const i = f.next_arg_index;3239 const i = f.next_arg_index;
3007 f.next_arg_index += 1;3240 f.next_arg_index += 1;
3008 return .{ .arg = i };3241 return if (inst_cty != try f.object.dg.typeToIndex(inst_ty, .complete))
3242 .{ .arg_array = i }
3243 else
3244 .{ .arg = i };
3009}3245}
30103246
3011fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {3247fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3115,7 +3351,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3115,7 +3351,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3115 const ret_val = if (is_array) ret_val: {3351 const ret_val = if (is_array) ret_val: {
3116 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));3352 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
3117 try writer.writeAll("memcpy(");3353 try writer.writeAll("memcpy(");
3118 try f.writeCValueMember(writer, array_local, .{ .field = 0 });3354 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
3119 try writer.writeAll(", ");3355 try writer.writeAll(", ");
3120 if (deref)3356 if (deref)
3121 try f.writeCValueDeref(writer, operand)3357 try f.writeCValueDeref(writer, operand)
...@@ -3135,14 +3371,13 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3135,14 +3371,13 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3135 try f.writeCValue(writer, ret_val, .Other);3371 try f.writeCValue(writer, ret_val, .Other);
3136 try writer.writeAll(";\n");3372 try writer.writeAll(";\n");
3137 if (is_array) {3373 if (is_array) {
3138 try freeLocal(f, inst, ret_val.local, 0);3374 try freeLocal(f, inst, ret_val.new_local, 0);
3139 }3375 }
3140 } else {3376 } else {
3141 try reap(f, inst, &.{un_op});3377 try reap(f, inst, &.{un_op});
3142 if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {3378 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked)
3143 // Not even allowed to return void in a naked function.3379 // Not even allowed to return void in a naked function.
3144 try writer.writeAll("return;\n");3380 try writer.writeAll("return;\n");
3145 }
3146 }3381 }
3147 return CValue.none;3382 return CValue.none;
3148}3383}
...@@ -3344,7 +3579,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3344,7 +3579,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3344 try f.renderTypecast(writer, src_ty);3579 try f.renderTypecast(writer, src_ty);
3345 try writer.writeAll("))");3580 try writer.writeAll("))");
3346 if (src_val == .constant) {3581 if (src_val == .constant) {
3347 try freeLocal(f, inst, array_src.local, 0);3582 try freeLocal(f, inst, array_src.new_local, 0);
3348 }3583 }
3349 } else if (ptr_info.host_size != 0) {3584 } else if (ptr_info.host_size != 0) {
3350 const host_bits = ptr_info.host_size * 8;3585 const host_bits = ptr_info.host_size * 8;
...@@ -3770,8 +4005,12 @@ fn airCall(...@@ -3770,8 +4005,12 @@ fn airCall(
3770 modifier: std.builtin.CallModifier,4005 modifier: std.builtin.CallModifier,
3771) !CValue {4006) !CValue {
3772 // Not even allowed to call panic in a naked function.4007 // Not even allowed to call panic in a naked function.
3773 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;4008 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
4009
3774 const gpa = f.object.dg.gpa;4010 const gpa = f.object.dg.gpa;
4011 const module = f.object.dg.module;
4012 const target = module.getTarget();
4013 const writer = f.object.writer();
37754014
3776 switch (modifier) {4015 switch (modifier) {
3777 .auto => {},4016 .auto => {},
...@@ -3786,8 +4025,28 @@ fn airCall(...@@ -3786,8 +4025,28 @@ fn airCall(
37864025
3787 const resolved_args = try gpa.alloc(CValue, args.len);4026 const resolved_args = try gpa.alloc(CValue, args.len);
3788 defer gpa.free(resolved_args);4027 defer gpa.free(resolved_args);
3789 for (args, 0..) |arg, i| {4028 for (resolved_args, args) |*resolved_arg, arg| {
3790 resolved_args[i] = try f.resolveInst(arg);4029 const arg_ty = f.air.typeOf(arg);
4030 const arg_cty = try f.object.dg.typeToIndex(arg_ty, .parameter);
4031 if (f.object.dg.indexToCType(arg_cty).tag() == .void) {
4032 resolved_arg.* = .none;
4033 continue;
4034 }
4035 resolved_arg.* = try f.resolveInst(arg);
4036 if (arg_cty != try f.object.dg.typeToIndex(arg_ty, .complete)) {
4037 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
4038 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
4039
4040 const array_local = try f.allocLocal(inst, try lowered_arg_ty.copy(f.arena.allocator()));
4041 try writer.writeAll("memcpy(");
4042 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4043 try writer.writeAll(", ");
4044 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4045 try writer.writeAll(", sizeof(");
4046 try f.renderTypecast(writer, lowered_arg_ty);
4047 try writer.writeAll("));\n");
4048 resolved_arg.* = array_local;
4049 }
3791 }4050 }
37924051
3793 const callee = try f.resolveInst(pl_op.operand);4052 const callee = try f.resolveInst(pl_op.operand);
...@@ -3804,9 +4063,7 @@ fn airCall(...@@ -3804,9 +4063,7 @@ fn airCall(
3804 .Pointer => callee_ty.childType(),4063 .Pointer => callee_ty.childType(),
3805 else => unreachable,4064 else => unreachable,
3806 };4065 };
3807 const writer = f.object.writer();
38084066
3809 const target = f.object.dg.module.getTarget();
3810 const ret_ty = fn_ty.fnReturnType();4067 const ret_ty = fn_ty.fnReturnType();
3811 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;4068 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3812 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);4069 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
...@@ -3841,7 +4098,7 @@ fn airCall(...@@ -3841,7 +4098,7 @@ fn airCall(
3841 else => break :known,4098 else => break :known,
3842 };4099 };
3843 };4100 };
3844 name = f.object.dg.module.declPtr(fn_decl).name;4101 name = module.declPtr(fn_decl).name;
3845 try f.object.dg.renderDeclName(writer, fn_decl, 0);4102 try f.object.dg.renderDeclName(writer, fn_decl, 0);
3846 break :callee;4103 break :callee;
3847 }4104 }
...@@ -3851,22 +4108,11 @@ fn airCall(...@@ -3851,22 +4108,11 @@ fn airCall(
38514108
3852 try writer.writeByte('(');4109 try writer.writeByte('(');
3853 var args_written: usize = 0;4110 var args_written: usize = 0;
3854 for (args, 0..) |arg, arg_i| {4111 for (resolved_args) |resolved_arg| {
3855 const ty = f.air.typeOf(arg);4112 if (resolved_arg == .none) continue;
3856 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;4113 if (args_written != 0) try writer.writeAll(", ");
3857 if (args_written != 0) {4114 try f.writeCValue(writer, resolved_arg, .FunctionArgument);
3858 try writer.writeAll(", ");4115 if (resolved_arg == .new_local) try freeLocal(f, inst, resolved_arg.new_local, 0);
3859 }
3860 if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and
3861 ty.isCPtr() and ty.childType().tag() == .u8)
3862 {
3863 // Corresponds with hack in renderType .Pointer case.
3864 try writer.writeAll("(char");
3865 if (ty.isConstPtr()) try writer.writeAll(" const");
3866 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
3867 try writer.writeAll(" *)");
3868 }
3869 try f.writeCValue(writer, resolved_args[arg_i], .FunctionArgument);
3870 args_written += 1;4116 args_written += 1;
3871 }4117 }
3872 try writer.writeAll(");\n");4118 try writer.writeAll(");\n");
...@@ -3879,11 +4125,11 @@ fn airCall(...@@ -3879,11 +4125,11 @@ fn airCall(
3879 try writer.writeAll("memcpy(");4125 try writer.writeAll("memcpy(");
3880 try f.writeCValue(writer, array_local, .FunctionArgument);4126 try f.writeCValue(writer, array_local, .FunctionArgument);
3881 try writer.writeAll(", ");4127 try writer.writeAll(", ");
3882 try f.writeCValueMember(writer, result_local, .{ .field = 0 });4128 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
3883 try writer.writeAll(", sizeof(");4129 try writer.writeAll(", sizeof(");
3884 try f.renderTypecast(writer, ret_ty);4130 try f.renderTypecast(writer, ret_ty);
3885 try writer.writeAll("));\n");4131 try writer.writeAll("));\n");
3886 try freeLocal(f, inst, result_local.local, 0);4132 try freeLocal(f, inst, result_local.new_local, 0);
3887 break :r array_local;4133 break :r array_local;
3888 };4134 };
38894135
...@@ -4147,7 +4393,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4147,7 +4393,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4147 }4393 }
41484394
4149 if (operand == .constant) {4395 if (operand == .constant) {
4150 try freeLocal(f, inst, operand_lval.local, 0);4396 try freeLocal(f, inst, operand_lval.new_local, 0);
4151 }4397 }
41524398
4153 return local;4399 return local;
...@@ -4193,7 +4439,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4193,7 +4439,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
41934439
4194fn airUnreach(f: *Function) !CValue {4440fn airUnreach(f: *Function) !CValue {
4195 // Not even allowed to call unreachable in a naked function.4441 // Not even allowed to call unreachable in a naked function.
4196 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;4442 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
41974443
4198 try f.object.writer().writeAll("zig_unreachable();\n");4444 try f.object.writer().writeAll("zig_unreachable();\n");
4199 return CValue.none;4445 return CValue.none;
...@@ -4667,7 +4913,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4667,7 +4913,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4667 const is_reg = constraint[1] == '{';4913 const is_reg = constraint[1] == '{';
4668 if (is_reg) {4914 if (is_reg) {
4669 try f.writeCValueDeref(writer, if (output == .none)4915 try f.writeCValueDeref(writer, if (output == .none)
4670 CValue{ .local_ref = local.local }4916 CValue{ .local_ref = local.new_local }
4671 else4917 else
4672 try f.resolveInst(output));4918 try f.resolveInst(output));
4673 try writer.writeAll(" = ");4919 try writer.writeAll(" = ");
...@@ -4967,18 +5213,20 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -4967,18 +5213,20 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
4967 else => .none,5213 else => .none,
4968 };5214 };
49695215
4970 const FieldLoc = union(enum) {5216 const field_loc: union(enum) {
4971 begin: void,5217 begin: void,
4972 field: CValue,5218 field: CValue,
4973 end: void,5219 end: void,
4974 };5220 } = switch (struct_ty.tag()) {
4975 const field_loc = switch (struct_ty.tag()) {5221 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
4976 .@"struct" => switch (struct_ty.containerLayout()) {5222 .Auto, .Extern => for (index..struct_ty.structFieldCount()) |field_i| {
4977 .Auto, .Extern => for (struct_ty.structFields().values()[index..], 0..) |field, offset| {5223 if (!struct_ty.structFieldIsComptime(field_i) and
4978 if (field.ty.hasRuntimeBitsIgnoreComptime()) break FieldLoc{ .field = .{5224 struct_ty.structFieldType(field_i).hasRuntimeBitsIgnoreComptime())
4979 .identifier = struct_ty.structFieldName(index + offset),5225 break .{ .field = if (struct_ty.isSimpleTuple())
4980 } };5226 .{ .field = field_i }
4981 } else @as(FieldLoc, .end),5227 else
5228 .{ .identifier = struct_ty.structFieldName(field_i) } };
5229 } else .end,
4982 .Packed => if (field_ptr_info.data.host_size == 0) {5230 .Packed => if (field_ptr_info.data.host_size == 0) {
4983 const target = f.object.dg.module.getTarget();5231 const target = f.object.dg.module.getTarget();
49845232
...@@ -5003,27 +5251,15 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -5003,27 +5251,15 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
5003 try f.writeCValue(writer, struct_ptr, .Other);5251 try f.writeCValue(writer, struct_ptr, .Other);
5004 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});5252 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5005 return local;5253 return local;
5006 } else @as(FieldLoc, .begin),5254 } else .begin,
5007 },5255 },
5008 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {5256 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
5009 try f.writeCValue(writer, struct_ptr, .Other);5257 try f.writeCValue(writer, struct_ptr, .Other);
5010 try writer.writeAll(";\n");5258 try writer.writeAll(";\n");
5011 return local;5259 return local;
5012 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) FieldLoc{ .field = .{5260 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) .{ .field = .{
5013 .identifier = struct_ty.unionFields().keys()[index],5261 .identifier = struct_ty.unionFields().keys()[index],
5014 } } else @as(FieldLoc, .end),5262 } } else .end,
5015 .tuple, .anon_struct => field_name: {
5016 const tuple = struct_ty.tupleFields();
5017 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
5018
5019 var id: usize = 0;
5020 break :field_name for (tuple.values, 0..) |value, i| {
5021 if (value.tag() != .unreachable_value) continue;
5022 if (!tuple.types[i].hasRuntimeBitsIgnoreComptime()) continue;
5023 if (i >= index) break FieldLoc{ .field = .{ .field = id } };
5024 id += 1;
5025 } else @as(FieldLoc, .end);
5026 },
5027 else => unreachable,5263 else => unreachable,
5028 };5264 };
50295265
...@@ -5076,8 +5312,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5076,8 +5312,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5076 };5312 };
50775313
5078 const field_name: CValue = switch (struct_ty.tag()) {5314 const field_name: CValue = switch (struct_ty.tag()) {
5079 .@"struct" => switch (struct_ty.containerLayout()) {5315 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5080 .Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) },5316 .Auto, .Extern => if (struct_ty.isSimpleTuple())
5317 .{ .field = extra.field_index }
5318 else
5319 .{ .identifier = struct_ty.structFieldName(extra.field_index) },
5081 .Packed => {5320 .Packed => {
5082 const struct_obj = struct_ty.castTag(.@"struct").?.data;5321 const struct_obj = struct_ty.castTag(.@"struct").?.data;
5083 const int_info = struct_ty.intInfo(target);5322 const int_info = struct_ty.intInfo(target);
...@@ -5135,13 +5374,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5135,13 +5374,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
51355374
5136 const local = try f.allocLocal(inst, inst_ty);5375 const local = try f.allocLocal(inst, inst_ty);
5137 try writer.writeAll("memcpy(");5376 try writer.writeAll("memcpy(");
5138 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);5377 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5139 try writer.writeAll(", ");5378 try writer.writeAll(", ");
5140 try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument);5379 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5141 try writer.writeAll(", sizeof(");5380 try writer.writeAll(", sizeof(");
5142 try f.renderTypecast(writer, inst_ty);5381 try f.renderTypecast(writer, inst_ty);
5143 try writer.writeAll("));\n");5382 try writer.writeAll("));\n");
5144 try freeLocal(f, inst, temp_local.local, 0);5383 try freeLocal(f, inst, temp_local.new_local, 0);
5145 return local;5384 return local;
5146 },5385 },
5147 },5386 },
...@@ -5165,22 +5404,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5165,22 +5404,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5165 try writer.writeAll("));\n");5404 try writer.writeAll("));\n");
51665405
5167 if (struct_byval == .constant) {5406 if (struct_byval == .constant) {
5168 try freeLocal(f, inst, operand_lval.local, 0);5407 try freeLocal(f, inst, operand_lval.new_local, 0);
5169 }5408 }
51705409
5171 return local;5410 return local;
5172 } else .{5411 } else .{
5173 .identifier = struct_ty.unionFields().keys()[extra.field_index],5412 .identifier = struct_ty.unionFields().keys()[extra.field_index],
5174 },5413 },
5175 .tuple, .anon_struct => blk: {
5176 const tuple = struct_ty.tupleFields();
5177 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
5178
5179 var id: usize = 0;
5180 for (tuple.values[0..extra.field_index]) |value|
5181 id += @boolToInt(value.tag() == .unreachable_value);
5182 break :blk .{ .field = id };
5183 },
5184 else => unreachable,5414 else => unreachable,
5185 };5415 };
51865416
...@@ -5765,7 +5995,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5765,7 +5995,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5765 }5995 }
57665996
5767 if (f.liveness.isUnused(inst)) {5997 if (f.liveness.isUnused(inst)) {
5768 try freeLocal(f, inst, local.local, 0);5998 try freeLocal(f, inst, local.new_local, 0);
5769 return CValue.none;5999 return CValue.none;
5770 }6000 }
57716001
...@@ -5808,7 +6038,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5808,7 +6038,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
5808 try writer.writeAll(");\n");6038 try writer.writeAll(");\n");
58096039
5810 if (f.liveness.isUnused(inst)) {6040 if (f.liveness.isUnused(inst)) {
5811 try freeLocal(f, inst, local.local, 0);6041 try freeLocal(f, inst, local.new_local, 0);
5812 return CValue.none;6042 return CValue.none;
5813 }6043 }
58146044
...@@ -5905,7 +6135,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5905,7 +6135,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
5905 try writer.writeAll(";\n");6135 try writer.writeAll(";\n");
59066136
5907 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });6137 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
5908 try freeLocal(f, inst, index.local, 0);6138 try freeLocal(f, inst, index.new_local, 0);
59096139
5910 return CValue.none;6140 return CValue.none;
5911 }6141 }
...@@ -6222,7 +6452,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6222,7 +6452,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
62226452
6223 try writer.writeAll(";\n");6453 try writer.writeAll(";\n");
62246454
6225 try freeLocal(f, inst, it.local, 0);6455 try freeLocal(f, inst, it.new_local, 0);
62266456
6227 return accum;6457 return accum;
6228}6458}
...@@ -6235,8 +6465,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6235,8 +6465,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6235 const gpa = f.object.dg.gpa;6465 const gpa = f.object.dg.gpa;
6236 const resolved_elements = try gpa.alloc(CValue, elements.len);6466 const resolved_elements = try gpa.alloc(CValue, elements.len);
6237 defer gpa.free(resolved_elements);6467 defer gpa.free(resolved_elements);
6238 for (elements, 0..) |element, i| {6468 for (resolved_elements, elements) |*resolved_element, element| {
6239 resolved_elements[i] = try f.resolveInst(element);6469 resolved_element.* = try f.resolveInst(element);
6240 }6470 }
6241 {6471 {
6242 var bt = iterateBigTomb(f, inst);6472 var bt = iterateBigTomb(f, inst);
...@@ -6275,46 +6505,47 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6275,46 +6505,47 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6275 try writer.writeAll(")");6505 try writer.writeAll(")");
6276 try writer.writeByte('{');6506 try writer.writeByte('{');
6277 var empty = true;6507 var empty = true;
6278 for (elements, 0..) |element, index| {6508 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6279 if (inst_ty.structFieldValueComptime(index)) |_| continue;6509 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
62806510
6281 if (!empty) try writer.writeAll(", ");6511 if (!empty) try writer.writeAll(", ");
6282 if (!inst_ty.isTupleOrAnonStruct()) {6512
6283 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});6513 const field_name: CValue = if (inst_ty.isSimpleTuple())
6284 }6514 .{ .field = field_i }
6515 else
6516 .{ .identifier = inst_ty.structFieldName(field_i) };
6517 try writer.writeByte('.');
6518 try f.object.dg.writeCValue(writer, field_name);
6519 try writer.writeAll(" = ");
62856520
6286 const element_ty = f.air.typeOf(element);6521 const element_ty = f.air.typeOf(element);
6287 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {6522 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
6288 .Array => CValue{ .undef = element_ty },6523 .Array => CValue{ .undef = element_ty },
6289 else => resolved_elements[index],6524 else => resolved_element,
6290 }, .Initializer);6525 }, .Initializer);
6291 empty = false;6526 empty = false;
6292 }6527 }
6293 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
6294 try writer.writeAll("};\n");6528 try writer.writeAll("};\n");
62956529
6296 var field_id: usize = 0;6530 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6297 for (elements, 0..) |element, index| {6531 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
6298 if (inst_ty.structFieldValueComptime(index)) |_| continue;
62996532
6300 const element_ty = f.air.typeOf(element);6533 const element_ty = f.air.typeOf(element);
6301 if (element_ty.zigTypeTag() != .Array) continue;6534 if (element_ty.zigTypeTag() != .Array) continue;
63026535
6303 const field_name = if (inst_ty.isTupleOrAnonStruct())6536 const field_name: CValue = if (inst_ty.isSimpleTuple())
6304 CValue{ .field = field_id }6537 .{ .field = field_i }
6305 else6538 else
6306 CValue{ .identifier = inst_ty.structFieldName(index) };6539 .{ .identifier = inst_ty.structFieldName(field_i) };
63076540
6308 try writer.writeAll(";\n");6541 try writer.writeAll(";\n");
6309 try writer.writeAll("memcpy(");6542 try writer.writeAll("memcpy(");
6310 try f.writeCValueMember(writer, local, field_name);6543 try f.writeCValueMember(writer, local, field_name);
6311 try writer.writeAll(", ");6544 try writer.writeAll(", ");
6312 try f.writeCValue(writer, resolved_elements[index], .FunctionArgument);6545 try f.writeCValue(writer, resolved_element, .FunctionArgument);
6313 try writer.writeAll(", sizeof(");6546 try writer.writeAll(", sizeof(");
6314 try f.renderTypecast(writer, element_ty);6547 try f.renderTypecast(writer, element_ty);
6315 try writer.writeAll("));\n");6548 try writer.writeAll("));\n");
6316
6317 field_id += 1;
6318 }6549 }
6319 },6550 },
6320 .Packed => {6551 .Packed => {
...@@ -6332,7 +6563,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6332,7 +6563,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6332 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);6563 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
63336564
6334 var empty = true;6565 var empty = true;
6335 for (elements, 0..) |_, index| {6566 for (0..elements.len) |index| {
6336 const field_ty = inst_ty.structFieldType(index);6567 const field_ty = inst_ty.structFieldType(index);
6337 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;6568 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
63386569
...@@ -6381,13 +6612,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6381,13 +6612,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6381 empty = false;6612 empty = false;
6382 }6613 }
63836614
6384 if (empty) {
6385 try writer.writeByte('(');
6386 try f.renderTypecast(writer, inst_ty);
6387 try writer.writeByte(')');
6388 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
6389 }
6390
6391 try writer.writeAll(";\n");6615 try writer.writeAll(";\n");
6392 },6616 },
6393 },6617 },
...@@ -7020,17 +7244,20 @@ fn isByRef(ty: Type) bool {...@@ -7020,17 +7244,20 @@ fn isByRef(ty: Type) bool {
7020}7244}
70217245
7022const LowerFnRetTyBuffer = struct {7246const LowerFnRetTyBuffer = struct {
7247 names: [1][]const u8,
7023 types: [1]Type,7248 types: [1]Type,
7024 values: [1]Value,7249 values: [1]Value,
7025 payload: Type.Payload.Tuple,7250 payload: Type.Payload.AnonStruct,
7026};7251};
7027fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {7252fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {
7028 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);7253 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);
70297254
7030 if (lowersToArray(ret_ty, target)) {7255 if (lowersToArray(ret_ty, target)) {
7256 buffer.names = [1][]const u8{"array"};
7031 buffer.types = [1]Type{ret_ty};7257 buffer.types = [1]Type{ret_ty};
7032 buffer.values = [1]Value{Value.initTag(.unreachable_value)};7258 buffer.values = [1]Value{Value.initTag(.unreachable_value)};
7033 buffer.payload = .{ .data = .{7259 buffer.payload = .{ .data = .{
7260 .names = &buffer.names,
7034 .types = &buffer.types,7261 .types = &buffer.types,
7035 .values = &buffer.values,7262 .values = &buffer.values,
7036 } };7263 } };
...@@ -7086,7 +7313,7 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {...@@ -7086,7 +7313,7 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
7086 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;7313 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
7087 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;7314 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
7088 const local_index = switch (c_value) {7315 const local_index = switch (c_value) {
7089 .local => |l| l,7316 .local, .new_local => |l| l,
7090 else => return,7317 else => return,
7091 };7318 };
7092 try freeLocal(f, inst, local_index, ref_inst);7319 try freeLocal(f, inst, local_index, ref_inst);
...@@ -7161,8 +7388,8 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {...@@ -7161,8 +7388,8 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
7161}7388}
71627389
7163fn noticeBranchFrees(f: *Function, pre_locals_len: LocalIndex, inst: Air.Inst.Index) !void {7390fn noticeBranchFrees(f: *Function, pre_locals_len: LocalIndex, inst: Air.Inst.Index) !void {
7164 for (f.locals.items[pre_locals_len..], 0..) |*local, local_offset| {7391 for (f.locals.items[pre_locals_len..], pre_locals_len..) |*local, local_i| {
7165 const local_index = pre_locals_len + @intCast(LocalIndex, local_offset);7392 const local_index = @intCast(LocalIndex, local_i);
7166 if (f.allocs.contains(local_index)) continue; // allocs are not freeable7393 if (f.allocs.contains(local_index)) continue; // allocs are not freeable
71677394
7168 // free more deeply nested locals from other branches at current depth7395 // free more deeply nested locals from other branches at current depth
src/codegen/c/type.zig+707-265
...@@ -110,10 +110,16 @@ pub const CType = extern union {...@@ -110,10 +110,16 @@ pub const CType = extern union {
110 pointer_const_volatile,110 pointer_const_volatile,
111 array,111 array,
112 vector,112 vector,
113 fwd_anon_struct,
114 fwd_anon_union,
113 fwd_struct,115 fwd_struct,
114 fwd_union,116 fwd_union,
117 unnamed_struct,
118 unnamed_union,
119 packed_unnamed_struct,
120 packed_unnamed_union,
115 anon_struct,121 anon_struct,
116 packed_anon_struct,122 anon_union,
117 @"struct",123 @"struct",
118 @"union",124 @"union",
119 packed_struct,125 packed_struct,
...@@ -183,14 +189,22 @@ pub const CType = extern union {...@@ -183,14 +189,22 @@ pub const CType = extern union {
183 .vector,189 .vector,
184 => Payload.Sequence,190 => Payload.Sequence,
185191
192 .fwd_anon_struct,
193 .fwd_anon_union,
194 => Payload.Fields,
195
186 .fwd_struct,196 .fwd_struct,
187 .fwd_union,197 .fwd_union,
188 => Payload.FwdDecl,198 => Payload.FwdDecl,
189199
190 .anon_struct,200 .unnamed_struct,
191 .packed_anon_struct,201 .unnamed_union,
192 => Payload.Fields,202 .packed_unnamed_struct,
203 .packed_unnamed_union,
204 => Payload.Unnamed,
193205
206 .anon_struct,
207 .anon_union,
194 .@"struct",208 .@"struct",
195 .@"union",209 .@"union",
196 .packed_struct,210 .packed_struct,
...@@ -229,14 +243,55 @@ pub const CType = extern union {...@@ -229,14 +243,55 @@ pub const CType = extern union {
229 base: Payload,243 base: Payload,
230 data: Data,244 data: Data,
231245
232 const Data = []const Field;246 pub const Data = []const Field;
233 const Field = struct {247 pub const Field = struct {
234 name: [*:0]const u8,248 name: [*:0]const u8,
235 type: Index,249 type: Index,
236 alignas: u32,250 alignas: AlignAs,
251 };
252 pub const AlignAs = struct {
253 @"align": std.math.Log2Int(u32),
254 abi: std.math.Log2Int(u32),
255
256 pub fn init(alignment: u32, abi_alignment: u32) AlignAs {
257 assert(std.math.isPowerOfTwo(alignment));
258 assert(std.math.isPowerOfTwo(abi_alignment));
259 return .{
260 .@"align" = std.math.log2_int(u32, alignment),
261 .abi = std.math.log2_int(u32, abi_alignment),
262 };
263 }
264 pub fn abiAlign(ty: Type, target: Target) AlignAs {
265 const abi_align = ty.abiAlignment(target);
266 return init(abi_align, abi_align);
267 }
268 pub fn fieldAlign(struct_ty: Type, field_i: usize, target: Target) AlignAs {
269 return init(
270 struct_ty.structFieldAlign(field_i, target),
271 struct_ty.structFieldType(field_i).abiAlignment(target),
272 );
273 }
274 pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs {
275 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
276 const union_payload_align = union_obj.abiAlignment(target, false);
277 return init(union_payload_align, union_payload_align);
278 }
279
280 pub fn getAlign(self: AlignAs) u32 {
281 return @as(u32, 1) << self.@"align";
282 }
237 };283 };
238 };284 };
239285
286 pub const Unnamed = struct {
287 base: Payload,
288 data: struct {
289 fields: Fields.Data,
290 owner_decl: Module.Decl.Index,
291 id: u32,
292 },
293 };
294
240 pub const Aggregate = struct {295 pub const Aggregate = struct {
241 base: Payload,296 base: Payload,
242 data: struct {297 data: struct {
...@@ -259,22 +314,23 @@ pub const CType = extern union {...@@ -259,22 +314,23 @@ pub const CType = extern union {
259 arena: std.heap.ArenaAllocator.State = .{},314 arena: std.heap.ArenaAllocator.State = .{},
260 set: Set = .{},315 set: Set = .{},
261316
262 const Set = struct {317 pub const Set = struct {
263 const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext32, true);318 pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext32, true);
264319
265 map: Map = .{},320 map: Map = .{},
266321
267 fn indexToCType(self: Set, index: Index) CType {322 pub fn indexToCType(self: Set, index: Index) CType {
268 if (index < Tag.no_payload_count) return initTag(@intToEnum(Tag, index));323 if (index < Tag.no_payload_count) return initTag(@intToEnum(Tag, index));
269 return self.map.keys()[index - Tag.no_payload_count];324 return self.map.keys()[index - Tag.no_payload_count];
270 }325 }
271326
272 fn indexToHash(self: Set, index: Index) Map.Hash {327 pub fn indexToHash(self: Set, index: Index) Map.Hash {
273 if (index < Tag.no_payload_count) return self.indexToCType(index).hash(self);328 if (index < Tag.no_payload_count)
329 return (HashContext32{ .store = &self }).hash(self.indexToCType(index));
274 return self.map.entries.items(.hash)[index - Tag.no_payload_count];330 return self.map.entries.items(.hash)[index - Tag.no_payload_count];
275 }331 }
276332
277 fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {333 pub fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {
278 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } };334 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } };
279335
280 var convert: Convert = undefined;336 var convert: Convert = undefined;
...@@ -298,21 +354,27 @@ pub const CType = extern union {...@@ -298,21 +354,27 @@ pub const CType = extern union {
298 return self.arena.child_allocator;354 return self.arena.child_allocator;
299 }355 }
300356
301 fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {357 pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
302 const t = cty.tag();358 const t = cty.tag();
303 if (@enumToInt(t) < Tag.no_payload_count) return @intCast(Index, @enumToInt(t));359 if (@enumToInt(t) < Tag.no_payload_count) return @intCast(Index, @enumToInt(t));
304360
305 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });361 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
306 if (!gop.found_existing) gop.key_ptr.* = cty;362 if (!gop.found_existing) gop.key_ptr.* = cty;
307 if (std.debug.runtime_safety) {363 if (std.debug.runtime_safety) {
308 const key = self.set.map.entries.items(.key)[gop.index];364 const key = &self.set.map.entries.items(.key)[gop.index];
309 assert(key.eql(cty));365 assert(key == gop.key_ptr);
366 assert(cty.eql(key.*));
310 assert(cty.hash(self.set) == key.hash(self.set));367 assert(cty.hash(self.set) == key.hash(self.set));
311 }368 }
312 return @intCast(Index, Tag.no_payload_count + gop.index);369 return @intCast(Index, Tag.no_payload_count + gop.index);
313 }370 }
314371
315 fn typeToIndex(self: *Promoted, ty: Type, mod: *Module, kind: Kind) Allocator.Error!Index {372 pub fn typeToIndex(
373 self: *Promoted,
374 ty: Type,
375 mod: *Module,
376 kind: Kind,
377 ) Allocator.Error!Index {
316 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .mod = mod } };378 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .mod = mod } };
317379
318 var convert: Convert = undefined;380 var convert: Convert = undefined;
...@@ -337,9 +399,10 @@ pub const CType = extern union {...@@ -337,9 +399,10 @@ pub const CType = extern union {
337 .lookup = lookup.freeze(),399 .lookup = lookup.freeze(),
338 .convert = &convert,400 .convert = &convert,
339 };401 };
340 const key = self.set.map.entries.items(.key)[gop.index];402 const cty = &self.set.map.entries.items(.key)[gop.index];
341 assert(adapter.eql(ty, key));403 assert(cty == gop.key_ptr);
342 assert(adapter.hash(ty) == key.hash(self.set));404 assert(adapter.eql(ty, cty.*));
405 assert(adapter.hash(ty) == cty.hash(self.set));
343 }406 }
344 return @intCast(Index, Tag.no_payload_count + gop.index);407 return @intCast(Index, Tag.no_payload_count + gop.index);
345 }408 }
...@@ -358,21 +421,25 @@ pub const CType = extern union {...@@ -358,21 +421,25 @@ pub const CType = extern union {
358 return self.set.indexToCType(index);421 return self.set.indexToCType(index);
359 }422 }
360423
424 pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
425 return self.set.indexToHash(index);
426 }
427
361 pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {428 pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
362 var promoted = self.promote(gpa);429 var promoted = self.promote(gpa);
363 defer self.demote(promoted);430 defer self.demote(promoted);
364 return promoted.cTypeToIndex(cty);431 return promoted.cTypeToIndex(cty);
365 }432 }
366433
367 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module) !CType {434 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !CType {
368 const idx = try self.typeToIndex(gpa, ty, mod);435 const idx = try self.typeToIndex(gpa, ty, mod, kind);
369 return self.indexToCType(idx);436 return self.indexToCType(idx);
370 }437 }
371438
372 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module) !Index {439 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !Index {
373 var promoted = self.promote(gpa);440 var promoted = self.promote(gpa);
374 defer self.demote(promoted);441 defer self.demote(promoted);
375 return promoted.typeToIndex(ty, mod, .complete);442 return promoted.typeToIndex(ty, mod, kind);
376 }443 }
377444
378 pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {445 pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
...@@ -389,8 +456,16 @@ pub const CType = extern union {...@@ -389,8 +456,16 @@ pub const CType = extern union {
389 _ = promoted.arena.reset(.free_all);456 _ = promoted.arena.reset(.free_all);
390 }457 }
391458
392 pub fn shrinkToFit(self: *Store, gpa: Allocator) void {459 pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
393 self.set.map.shrinkAndFree(gpa, self.set.map.count());460 self.set.map.shrinkRetainingCapacity(gpa, new_len);
461 }
462
463 pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
464 self.set.map.shrinkAndFree(gpa, new_len);
465 }
466
467 pub fn count(self: Store) usize {
468 return self.set.map.count();
394 }469 }
395470
396 pub fn move(self: *Store) Store {471 pub fn move(self: *Store) Store {
...@@ -407,7 +482,37 @@ pub const CType = extern union {...@@ -407,7 +482,37 @@ pub const CType = extern union {
407 }482 }
408 };483 };
409484
485 pub fn isPacked(self: CType) bool {
486 return switch (self.tag()) {
487 else => false,
488 .packed_unnamed_struct,
489 .packed_unnamed_union,
490 .packed_struct,
491 .packed_union,
492 => true,
493 };
494 }
495
496 pub fn fields(self: CType) Payload.Fields.Data {
497 return if (self.cast(Payload.Aggregate)) |pl|
498 pl.data.fields
499 else if (self.cast(Payload.Unnamed)) |pl|
500 pl.data.fields
501 else if (self.cast(Payload.Fields)) |pl|
502 pl.data
503 else
504 unreachable;
505 }
506
410 pub fn eql(lhs: CType, rhs: CType) bool {507 pub fn eql(lhs: CType, rhs: CType) bool {
508 return lhs.eqlContext(rhs, struct {
509 pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
510 return lhs_idx == rhs_idx;
511 }
512 }{});
513 }
514
515 pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
411 // As a shortcut, if the small tags / addresses match, we're done.516 // As a shortcut, if the small tags / addresses match, we're done.
412 if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;517 if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
413518
...@@ -458,35 +563,52 @@ pub const CType = extern union {...@@ -458,35 +563,52 @@ pub const CType = extern union {
458 .pointer_const,563 .pointer_const,
459 .pointer_volatile,564 .pointer_volatile,
460 .pointer_const_volatile,565 .pointer_const_volatile,
461 => lhs.cast(Payload.Child).?.data == rhs.cast(Payload.Child).?.data,566 => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
462567
463 .array,568 .array,
464 .vector,569 .vector,
465 => std.meta.eql(lhs.cast(Payload.Sequence).?.data, rhs.cast(Payload.Sequence).?.data),570 => {
466571 const lhs_data = lhs.cast(Payload.Sequence).?.data;
467 .fwd_struct,572 const rhs_data = rhs.cast(Payload.Sequence).?.data;
468 .fwd_union,573 return lhs_data.len == rhs_data.len and
469 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,574 ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
575 },
470576
471 .anon_struct,577 .fwd_anon_struct,
472 .packed_anon_struct,578 .fwd_anon_union,
473 => {579 => {
474 const lhs_data = lhs.cast(Payload.Fields).?.data;580 const lhs_data = lhs.cast(Payload.Fields).?.data;
475 const rhs_data = rhs.cast(Payload.Fields).?.data;581 const rhs_data = rhs.cast(Payload.Fields).?.data;
476 if (lhs_data.len != rhs_data.len) return false;582 if (lhs_data.len != rhs_data.len) return false;
477 for (lhs_data, rhs_data) |lhs_field, rhs_field| {583 for (lhs_data, rhs_data) |lhs_field, rhs_field| {
478 if (lhs_field.type != rhs_field.type) return false;584 if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
479 if (lhs_field.alignas != rhs_field.alignas) return false;585 if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
480 if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false;586 if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false;
481 }587 }
482 return true;588 return true;
483 },589 },
484590
591 .fwd_struct,
592 .fwd_union,
593 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
594
595 .unnamed_struct,
596 .unnamed_union,
597 .packed_unnamed_struct,
598 .packed_unnamed_union,
599 => {
600 const lhs_data = lhs.cast(Payload.Unnamed).?.data;
601 const rhs_data = rhs.cast(Payload.Unnamed).?.data;
602 return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
603 },
604
605 .anon_struct,
606 .anon_union,
485 .@"struct",607 .@"struct",
486 .@"union",608 .@"union",
487 .packed_struct,609 .packed_struct,
488 .packed_union,610 .packed_union,
489 => std.meta.eql(611 => ctx.eqlIndex(
490 lhs.cast(Payload.Aggregate).?.data.fwd_decl,612 lhs.cast(Payload.Aggregate).?.data.fwd_decl,
491 rhs.cast(Payload.Aggregate).?.data.fwd_decl,613 rhs.cast(Payload.Aggregate).?.data.fwd_decl,
492 ),614 ),
...@@ -496,10 +618,10 @@ pub const CType = extern union {...@@ -496,10 +618,10 @@ pub const CType = extern union {
496 => {618 => {
497 const lhs_data = lhs.cast(Payload.Function).?.data;619 const lhs_data = lhs.cast(Payload.Function).?.data;
498 const rhs_data = rhs.cast(Payload.Function).?.data;620 const rhs_data = rhs.cast(Payload.Function).?.data;
499 if (lhs_data.return_type != rhs_data.return_type) return false;
500 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;621 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
501 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_cty, rhs_param_cty| {622 if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
502 if (lhs_param_cty != rhs_param_cty) return false;623 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
624 if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
503 }625 }
504 return true;626 return true;
505 },627 },
...@@ -568,18 +690,30 @@ pub const CType = extern union {...@@ -568,18 +690,30 @@ pub const CType = extern union {
568 store.indexToCType(data.elem_type).updateHasher(hasher, store);690 store.indexToCType(data.elem_type).updateHasher(hasher, store);
569 },691 },
570692
693 .fwd_anon_struct,
694 .fwd_anon_union,
695 => for (self.cast(Payload.Fields).?.data) |field| {
696 store.indexToCType(field.type).updateHasher(hasher, store);
697 hasher.update(mem.span(field.name));
698 autoHash(hasher, field.alignas.@"align");
699 },
700
571 .fwd_struct,701 .fwd_struct,
572 .fwd_union,702 .fwd_union,
573 => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),703 => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
574704
575 .anon_struct,705 .unnamed_struct,
576 .packed_anon_struct,706 .unnamed_union,
577 => for (self.cast(Payload.Fields).?.data) |field| {707 .packed_unnamed_struct,
578 store.indexToCType(field.type).updateHasher(hasher, store);708 .packed_unnamed_union,
579 hasher.update(mem.span(field.name));709 => {
580 autoHash(hasher, field.alignas);710 const data = self.cast(Payload.Unnamed).?.data;
711 autoHash(hasher, data.owner_decl);
712 autoHash(hasher, data.id);
581 },713 },
582714
715 .anon_struct,
716 .anon_union,
583 .@"struct",717 .@"struct",
584 .@"union",718 .@"union",
585 .packed_struct,719 .packed_struct,
...@@ -599,7 +733,7 @@ pub const CType = extern union {...@@ -599,7 +733,7 @@ pub const CType = extern union {
599 }733 }
600 }734 }
601735
602 pub const Kind = enum { forward, complete, global, parameter };736 pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
603737
604 const Convert = struct {738 const Convert = struct {
605 storage: union {739 storage: union {
...@@ -609,9 +743,11 @@ pub const CType = extern union {...@@ -609,9 +743,11 @@ pub const CType = extern union {
609 fwd: Payload.FwdDecl,743 fwd: Payload.FwdDecl,
610 anon: struct {744 anon: struct {
611 fields: [2]Payload.Fields.Field,745 fields: [2]Payload.Fields.Field,
612 pl: Payload.Fields,746 pl: union {
747 forward: Payload.Fields,
748 complete: Payload.Aggregate,
749 },
613 },750 },
614 agg: Payload.Aggregate,
615 },751 },
616 value: union(enum) {752 value: union(enum) {
617 tag: Tag,753 tag: Tag,
...@@ -716,6 +852,66 @@ pub const CType = extern union {...@@ -716,6 +852,66 @@ pub const CType = extern union {
716 }852 }
717 };853 };
718854
855 fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
856 const Field = Payload.Fields.Field;
857 const slice = self.storage.anon.fields[0..fields_len];
858 std.sort.sort(Field, slice, {}, struct {
859 fn before(_: void, lhs: Field, rhs: Field) bool {
860 return lhs.alignas.@"align" > rhs.alignas.@"align";
861 }
862 }.before);
863 return slice;
864 }
865
866 fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
867 switch (kind) {
868 .forward, .forward_parameter => {
869 self.storage.anon.pl = .{ .forward = .{
870 .base = .{ .tag = .fwd_anon_struct },
871 .data = self.sortFields(fields_len),
872 } };
873 self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
874 },
875 .complete, .parameter, .global => {
876 self.storage.anon.pl = .{ .complete = .{
877 .base = .{ .tag = .anon_struct },
878 .data = .{
879 .fields = self.sortFields(fields_len),
880 .fwd_decl = fwd_idx,
881 },
882 } };
883 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
884 },
885 .payload => unreachable,
886 }
887 }
888
889 fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
890 if (switch (kind) {
891 .forward_parameter => @as(Index, undefined),
892 .parameter => try lookup.typeToIndex(ty, .forward_parameter),
893 .forward, .complete, .global, .payload => unreachable,
894 }) |fwd_idx| {
895 if (try lookup.typeToIndex(ty, switch (kind) {
896 .forward_parameter => .forward,
897 .parameter => .complete,
898 .forward, .complete, .global, .payload => unreachable,
899 })) |array_idx| {
900 self.storage = .{ .anon = undefined };
901 self.storage.anon.fields[0] = .{
902 .name = "array",
903 .type = array_idx,
904 .alignas = Payload.Fields.AlignAs.abiAlign(ty, lookup.getTarget()),
905 };
906 self.initAnon(kind, fwd_idx, 1);
907 } else self.init(switch (kind) {
908 .forward_parameter => .fwd_anon_struct,
909 .parameter => .anon_struct,
910 .forward, .complete, .global, .payload => unreachable,
911 });
912 } else self.init(.anon_struct);
913 }
914
719 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {915 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
720 const target = lookup.getTarget();916 const target = lookup.getTarget();
721917
...@@ -739,17 +935,23 @@ pub const CType = extern union {...@@ -739,17 +935,23 @@ pub const CType = extern union {
739 switch (t) {935 switch (t) {
740 .void => unreachable,936 .void => unreachable,
741 else => self.init(t),937 else => self.init(t),
742 .array => {938 .array => switch (kind) {
743 const abi_size = ty.abiSize(target);939 .forward, .complete, .global => {
744 const abi_align = ty.abiAlignment(target);940 const abi_size = ty.abiSize(target);
745 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{941 const abi_align = ty.abiAlignment(target);
746 .len = @divExact(abi_size, abi_align),942 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
747 .elem_type = tagFromIntInfo(943 .len = @divExact(abi_size, abi_align),
748 .unsigned,944 .elem_type = tagFromIntInfo(
749 @intCast(u16, abi_align * 8),945 .unsigned,
750 ).toIndex(),946 @intCast(u16, abi_align * 8),
751 } } };947 ).toIndex(),
752 self.value = .{ .cty = initPayload(&self.storage.seq) };948 } } };
949 self.value = .{ .cty = initPayload(&self.storage.seq) };
950 },
951 .forward_parameter,
952 .parameter,
953 => try self.initArrayParameter(ty, kind, lookup),
954 .payload => unreachable,
753 },955 },
754 }956 }
755 },957 },
...@@ -782,165 +984,297 @@ pub const CType = extern union {...@@ -782,165 +984,297 @@ pub const CType = extern union {
782 else => unreachable,984 else => unreachable,
783 }),985 }),
784986
785 .Pointer => switch (ty.ptrSize()) {987 .Pointer => {
786 .Slice => {988 const info = ty.ptrInfo().data;
787 var buf: Type.SlicePtrFieldTypeBuffer = undefined;989 switch (info.size) {
788 const ptr_ty = ty.slicePtrFieldType(&buf);990 .Slice => {
789 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {991 if (switch (kind) {
790 self.storage = .{ .anon = .{ .fields = .{992 .forward, .forward_parameter => @as(Index, undefined),
791 .{993 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
792 .name = "ptr",994 .payload => unreachable,
793 .type = ptr_idx,995 }) |fwd_idx| {
794 .alignas = ptr_ty.abiAlignment(target),996 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
997 const ptr_ty = ty.slicePtrFieldType(&buf);
998 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
999 self.storage = .{ .anon = undefined };
1000 self.storage.anon.fields[0] = .{
1001 .name = "ptr",
1002 .type = ptr_idx,
1003 .alignas = Payload.Fields.AlignAs.abiAlign(ptr_ty, target),
1004 };
1005 self.storage.anon.fields[1] = .{
1006 .name = "len",
1007 .type = Tag.uintptr_t.toIndex(),
1008 .alignas = Payload.Fields.AlignAs.abiAlign(Type.usize, target),
1009 };
1010 self.initAnon(kind, fwd_idx, 2);
1011 } else self.init(switch (kind) {
1012 .forward, .forward_parameter => .fwd_anon_struct,
1013 .complete, .parameter, .global => .anon_struct,
1014 .payload => unreachable,
1015 });
1016 } else self.init(.anon_struct);
1017 },
1018
1019 .One, .Many, .C => {
1020 const t: Tag = switch (info.@"volatile") {
1021 false => switch (info.mutable) {
1022 true => .pointer,
1023 false => .pointer_const,
795 },1024 },
796 .{1025 true => switch (info.mutable) {
797 .name = "len",1026 true => .pointer_volatile,
798 .type = Tag.size_t.toIndex(),1027 false => .pointer_const_volatile,
799 .alignas = Type.usize.abiAlignment(target),
800 },1028 },
801 }, .pl = undefined } };
802 self.storage.anon.pl = .{
803 .base = .{ .tag = .anon_struct },
804 .data = self.storage.anon.fields[0..2],
805 };1029 };
806 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };
807 } else self.init(.anon_struct);
808 },
8091030
810 .One, .Many, .C => {1031 var host_int_pl = Type.Payload.Bits{
811 const t: Tag = switch (ty.isVolatilePtr()) {1032 .base = .{ .tag = .int_unsigned },
812 false => switch (ty.isConstPtr()) {1033 .data = info.host_size * 8,
813 false => .pointer,1034 };
814 true => .pointer_const,1035 const pointee_ty = if (info.host_size > 0)
815 },1036 Type.initPayload(&host_int_pl.base)
816 true => switch (ty.isConstPtr()) {1037 else
817 false => .pointer_volatile,1038 info.pointee_type;
818 true => .pointer_const_volatile,1039
819 },1040 if (if (info.size == .C and pointee_ty.tag() == .u8)
820 };1041 Tag.char.toIndex()
821 if (try lookup.typeToIndex(ty.childType(), .forward)) |child_idx| {1042 else
822 self.storage = .{ .child = .{ .base = .{ .tag = t }, .data = child_idx } };1043 try lookup.typeToIndex(pointee_ty, .forward)) |child_idx|
823 self.value = .{ .cty = initPayload(&self.storage.child) };1044 {
824 } else self.init(t);1045 self.storage = .{ .child = .{
825 },1046 .base = .{ .tag = t },
1047 .data = child_idx,
1048 } };
1049 self.value = .{ .cty = initPayload(&self.storage.child) };
1050 } else self.init(t);
1051 },
1052 }
826 },1053 },
8271054
828 .Struct, .Union => |zig_tag| if (ty.isTupleOrAnonStruct()) {1055 .Struct, .Union => |zig_tag| if (ty.containerLayout() == .Packed) {
1056 if (ty.castTag(.@"struct")) |struct_obj| {
1057 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
1058 } else {
1059 var buf: Type.Payload.Bits = .{
1060 .base = .{ .tag = .int_unsigned },
1061 .data = @intCast(u16, ty.bitSize(target)),
1062 };
1063 try self.initType(Type.initPayload(&buf.base), kind, lookup);
1064 }
1065 } else if (ty.isTupleOrAnonStruct()) {
829 if (lookup.isMutable()) {1066 if (lookup.isMutable()) {
830 for (0..ty.structFieldCount()) |field_i| {1067 for (0..ty.structFieldCount()) |field_i| {
831 const field_ty = ty.structFieldType(field_i);1068 const field_ty = ty.structFieldType(field_i);
832 if (ty.structFieldIsComptime(field_i) or1069 if (ty.structFieldIsComptime(field_i) or
833 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;1070 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
834 _ = try lookup.typeToIndex(field_ty, switch (kind) {1071 _ = try lookup.typeToIndex(field_ty, switch (kind) {
835 .forward, .complete, .parameter => .complete,1072 .forward, .forward_parameter => .forward,
1073 .complete, .parameter => .complete,
836 .global => .global,1074 .global => .global,
1075 .payload => unreachable,
837 });1076 });
838 }1077 }
1078 switch (kind) {
1079 .forward, .forward_parameter => {},
1080 .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
1081 .payload => unreachable,
1082 }
839 }1083 }
840 self.init(.anon_struct);1084 self.init(switch (kind) {
1085 .forward, .forward_parameter => .fwd_anon_struct,
1086 .complete, .parameter, .global => .anon_struct,
1087 .payload => unreachable,
1088 });
841 } else {1089 } else {
842 const is_struct = zig_tag == .Struct or ty.unionTagTypeSafety() != null;1090 const tag_ty = ty.unionTagTypeSafety();
1091 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1092 const is_struct = zig_tag == .Struct or is_tagged_union_wrapper;
843 switch (kind) {1093 switch (kind) {
844 .forward => {1094 .forward, .forward_parameter => {
845 self.storage = .{ .fwd = .{1095 self.storage = .{ .fwd = .{
846 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },1096 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
847 .data = ty.getOwnerDecl(),1097 .data = ty.getOwnerDecl(),
848 } };1098 } };
849 self.value = .{ .cty = initPayload(&self.storage.fwd) };1099 self.value = .{ .cty = initPayload(&self.storage.fwd) };
850 },1100 },
851 else => {1101 .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
852 if (lookup.isMutable()) {1102 const fwd_idx = try lookup.typeToIndex(ty, .forward);
853 for (0..switch (zig_tag) {1103 const payload_idx = try lookup.typeToIndex(ty, .payload);
854 .Struct => ty.structFieldCount(),1104 const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
855 .Union => ty.cast(Type.Payload.Union).?.data.fields.count(),1105 if (fwd_idx != null and payload_idx != null and tag_idx != null) {
856 else => unreachable,1106 self.storage = .{ .anon = undefined };
857 }) |field_i| {1107 var field_count: usize = 0;
858 const field_ty = ty.structFieldType(field_i);1108 if (payload_idx != Tag.void.toIndex()) {
859 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;1109 self.storage.anon.fields[field_count] = .{
1110 .name = "payload",
1111 .type = payload_idx.?,
1112 .alignas = Payload.Fields.AlignAs.unionPayloadAlign(ty, target),
1113 };
1114 field_count += 1;
1115 }
1116 if (tag_idx != Tag.void.toIndex()) {
1117 self.storage.anon.fields[field_count] = .{
1118 .name = "tag",
1119 .type = tag_idx.?,
1120 .alignas = Payload.Fields.AlignAs.abiAlign(tag_ty.?, target),
1121 };
1122 field_count += 1;
1123 }
1124 self.storage.anon.pl = .{ .complete = .{
1125 .base = .{ .tag = .@"struct" },
1126 .data = .{
1127 .fields = self.sortFields(field_count),
1128 .fwd_decl = fwd_idx.?,
1129 },
1130 } };
1131 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
1132 } else self.init(.@"struct");
1133 } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) {
1134 self.init(.void);
1135 } else {
1136 var is_packed = false;
1137 for (0..switch (zig_tag) {
1138 .Struct => ty.structFieldCount(),
1139 .Union => ty.unionFields().count(),
1140 else => unreachable,
1141 }) |field_i| {
1142 const field_ty = ty.structFieldType(field_i);
1143 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1144
1145 const field_align = Payload.Fields.AlignAs.fieldAlign(
1146 ty,
1147 field_i,
1148 target,
1149 );
1150 if (field_align.@"align" < field_align.abi) {
1151 is_packed = true;
1152 if (!lookup.isMutable()) break;
1153 }
1154
1155 if (lookup.isMutable()) {
860 _ = try lookup.typeToIndex(field_ty, switch (kind) {1156 _ = try lookup.typeToIndex(field_ty, switch (kind) {
861 .forward => unreachable,1157 .forward, .forward_parameter => unreachable,
862 .complete, .parameter => .complete,1158 .complete, .parameter, .payload => .complete,
863 .global => .global,1159 .global => .global,
864 });1160 });
865 }1161 }
866 _ = try lookup.typeToIndex(ty, .forward);
867 }1162 }
868 self.init(if (is_struct) .@"struct" else .@"union");1163 switch (kind) {
1164 .forward, .forward_parameter => unreachable,
1165 .complete, .parameter, .global => {
1166 _ = try lookup.typeToIndex(ty, .forward);
1167 self.init(if (is_struct)
1168 if (is_packed) .packed_struct else .@"struct"
1169 else if (is_packed) .packed_union else .@"union");
1170 },
1171 .payload => self.init(if (is_packed)
1172 .packed_unnamed_union
1173 else
1174 .unnamed_union),
1175 }
869 },1176 },
870 }1177 }
871 },1178 },
8721179
873 .Array, .Vector => |zig_tag| {1180 .Array, .Vector => |zig_tag| {
874 const t: Tag = switch (zig_tag) {1181 switch (kind) {
875 .Array => .array,1182 .forward, .complete, .global => {
876 .Vector => .vector,1183 const t: Tag = switch (zig_tag) {
877 else => unreachable,1184 .Array => .array,
878 };1185 .Vector => .vector,
879 if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {1186 else => unreachable,
880 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{1187 };
881 .len = ty.arrayLenIncludingSentinel(),1188 if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {
882 .elem_type = child_idx,1189 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
883 } } };1190 .len = ty.arrayLenIncludingSentinel(),
884 self.value = .{ .cty = initPayload(&self.storage.seq) };1191 .elem_type = child_idx,
885 } else self.init(t);1192 } } };
1193 self.value = .{ .cty = initPayload(&self.storage.seq) };
1194 } else self.init(t);
1195 },
1196 .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
1197 .payload => unreachable,
1198 }
886 },1199 },
8871200
888 .Optional => {1201 .Optional => {
889 var buf: Type.Payload.ElemType = undefined;1202 var buf: Type.Payload.ElemType = undefined;
890 const payload_ty = ty.optionalChild(&buf);1203 const payload_ty = ty.optionalChild(&buf);
891 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {1204 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
892 if (ty.optionalReprIsPayload())1205 if (ty.optionalReprIsPayload()) {
893 try self.initType(payload_ty, kind, lookup)1206 try self.initType(payload_ty, kind, lookup);
894 else if (try lookup.typeToIndex(payload_ty, kind)) |payload_idx| {1207 } else if (switch (kind) {
895 self.storage = .{ .anon = .{ .fields = .{1208 .forward, .forward_parameter => @as(Index, undefined),
896 .{1209 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1210 .payload => unreachable,
1211 }) |fwd_idx| {
1212 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1213 .forward, .forward_parameter => .forward,
1214 .complete, .parameter => .complete,
1215 .global => .global,
1216 .payload => unreachable,
1217 })) |payload_idx| {
1218 self.storage = .{ .anon = undefined };
1219 self.storage.anon.fields[0] = .{
897 .name = "payload",1220 .name = "payload",
898 .type = payload_idx,1221 .type = payload_idx,
899 .alignas = payload_ty.abiAlignment(target),1222 .alignas = Payload.Fields.AlignAs.abiAlign(payload_ty, target),
900 },1223 };
901 .{1224 self.storage.anon.fields[1] = .{
902 .name = "is_null",1225 .name = "is_null",
903 .type = Tag.bool.toIndex(),1226 .type = Tag.bool.toIndex(),
904 .alignas = Type.bool.abiAlignment(target),1227 .alignas = Payload.Fields.AlignAs.abiAlign(Type.bool, target),
905 },1228 };
906 }, .pl = undefined } };1229 self.initAnon(kind, fwd_idx, 2);
907 self.storage.anon.pl = .{1230 } else self.init(switch (kind) {
908 .base = .{ .tag = .anon_struct },1231 .forward, .forward_parameter => .fwd_anon_struct,
909 .data = self.storage.anon.fields[0..2],1232 .complete, .parameter, .global => .anon_struct,
910 };1233 .payload => unreachable,
911 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };1234 });
912 } else self.init(.anon_struct);1235 } else self.init(.anon_struct);
913 } else self.init(.bool);1236 } else self.init(.bool);
914 },1237 },
9151238
916 .ErrorUnion => {1239 .ErrorUnion => {
917 const payload_ty = ty.errorUnionPayload();1240 if (switch (kind) {
918 if (try lookup.typeToIndex(payload_ty, switch (kind) {1241 .forward, .forward_parameter => @as(Index, undefined),
919 .forward, .complete, .parameter => .complete,1242 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
920 .global => .global,1243 .payload => unreachable,
921 })) |payload_idx| {1244 }) |fwd_idx| {
922 const error_ty = ty.errorUnionSet();1245 const payload_ty = ty.errorUnionPayload();
923 if (payload_idx == Tag.void.toIndex())1246 if (try lookup.typeToIndex(payload_ty, switch (kind) {
924 try self.initType(error_ty, kind, lookup)1247 .forward, .forward_parameter => .forward,
925 else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {1248 .complete, .parameter => .complete,
926 self.storage = .{ .anon = .{ .fields = .{1249 .global => .global,
927 .{1250 .payload => unreachable,
1251 })) |payload_idx| {
1252 const error_ty = ty.errorUnionSet();
1253 if (payload_idx == Tag.void.toIndex()) {
1254 try self.initType(error_ty, kind, lookup);
1255 } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
1256 self.storage = .{ .anon = undefined };
1257 self.storage.anon.fields[0] = .{
928 .name = "payload",1258 .name = "payload",
929 .type = payload_idx,1259 .type = payload_idx,
930 .alignas = payload_ty.abiAlignment(target),1260 .alignas = Payload.Fields.AlignAs.abiAlign(payload_ty, target),
931 },1261 };
932 .{1262 self.storage.anon.fields[1] = .{
933 .name = "error",1263 .name = "error",
934 .type = error_idx,1264 .type = error_idx,
935 .alignas = error_ty.abiAlignment(target),1265 .alignas = Payload.Fields.AlignAs.abiAlign(error_ty, target),
936 },1266 };
937 }, .pl = undefined } };1267 self.initAnon(kind, fwd_idx, 2);
938 self.storage.anon.pl = .{1268 } else self.init(switch (kind) {
939 .base = .{ .tag = .anon_struct },1269 .forward, .forward_parameter => .fwd_anon_struct,
940 .data = self.storage.anon.fields[0..2],1270 .complete, .parameter, .global => .anon_struct,
941 };1271 .payload => unreachable,
942 self.value = .{ .cty = initPayload(&self.storage.anon.pl) };1272 });
943 } else self.init(.anon_struct);1273 } else self.init(switch (kind) {
1274 .forward, .forward_parameter => .fwd_anon_struct,
1275 .complete, .parameter, .global => .anon_struct,
1276 .payload => unreachable,
1277 });
944 } else self.init(.anon_struct);1278 } else self.init(.anon_struct);
945 },1279 },
9461280
...@@ -959,16 +1293,15 @@ pub const CType = extern union {...@@ -959,16 +1293,15 @@ pub const CType = extern union {
959 .Fn => {1293 .Fn => {
960 const info = ty.fnInfo();1294 const info = ty.fnInfo();
961 if (lookup.isMutable()) {1295 if (lookup.isMutable()) {
962 _ = try lookup.typeToIndex(info.return_type, switch (kind) {1296 const param_kind: Kind = switch (kind) {
963 .forward => .forward,1297 .forward, .forward_parameter => .forward_parameter,
964 .complete, .parameter, .global => .complete,1298 .complete, .parameter, .global => .parameter,
965 });1299 .payload => unreachable,
1300 };
1301 _ = try lookup.typeToIndex(info.return_type, param_kind);
966 for (info.param_types) |param_type| {1302 for (info.param_types) |param_type| {
967 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1303 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
968 _ = try lookup.typeToIndex(param_type, switch (kind) {1304 _ = try lookup.typeToIndex(param_type, param_kind);
969 .forward => .forward,
970 .complete, .parameter, .global => unreachable,
971 });
972 }1305 }
973 }1306 }
974 self.init(if (info.is_var_args) .varargs_function else .function);1307 self.init(if (info.is_var_args) .varargs_function else .function);
...@@ -977,16 +1310,33 @@ pub const CType = extern union {...@@ -977,16 +1310,33 @@ pub const CType = extern union {
977 }1310 }
978 };1311 };
9791312
980 fn copyFields(arena: Allocator, fields: Payload.Fields.Data) !Payload.Fields.Data {1313 pub fn copy(self: CType, arena: Allocator) !CType {
981 const new_fields = try arena.dupe(Payload.Fields.Field, fields);1314 return self.copyContext(struct {
982 for (new_fields) |*new_field| {1315 arena: Allocator,
983 new_field.name = try arena.dupeZ(u8, mem.span(new_field.name));1316 pub fn copyIndex(_: @This(), idx: Index) Index {
984 new_field.type = new_field.type;1317 return idx;
1318 }
1319 }{ .arena = arena });
1320 }
1321
1322 fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
1323 const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
1324 for (new_fields, old_fields) |*new_field, old_field| {
1325 new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
1326 new_field.type = ctx.copyIndex(old_field.type);
1327 new_field.alignas = old_field.alignas;
985 }1328 }
986 return new_fields;1329 return new_fields;
987 }1330 }
9881331
989 pub fn copy(self: CType, arena: Allocator) !CType {1332 fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
1333 const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
1334 for (new_param_types, old_param_types) |*new_param_type, old_param_type|
1335 new_param_type.* = ctx.copyIndex(old_param_type);
1336 return new_param_types;
1337 }
1338
1339 pub fn copyContext(self: CType, ctx: anytype) !CType {
990 switch (self.tag()) {1340 switch (self.tag()) {
991 .void,1341 .void,
992 .char,1342 .char,
...@@ -1032,8 +1382,8 @@ pub const CType = extern union {...@@ -1032,8 +1382,8 @@ pub const CType = extern union {
1032 .pointer_const_volatile,1382 .pointer_const_volatile,
1033 => {1383 => {
1034 const pl = self.cast(Payload.Child).?;1384 const pl = self.cast(Payload.Child).?;
1035 const new_pl = try arena.create(Payload.Child);1385 const new_pl = try ctx.arena.create(Payload.Child);
1036 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };1386 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
1037 return initPayload(new_pl);1387 return initPayload(new_pl);
1038 },1388 },
10391389
...@@ -1041,48 +1391,62 @@ pub const CType = extern union {...@@ -1041,48 +1391,62 @@ pub const CType = extern union {
1041 .vector,1391 .vector,
1042 => {1392 => {
1043 const pl = self.cast(Payload.Sequence).?;1393 const pl = self.cast(Payload.Sequence).?;
1044 const new_pl = try arena.create(Payload.Sequence);1394 const new_pl = try ctx.arena.create(Payload.Sequence);
1045 new_pl.* = .{1395 new_pl.* = .{
1046 .base = .{ .tag = pl.base.tag },1396 .base = .{ .tag = pl.base.tag },
1047 .data = .{ .len = pl.data.len, .elem_type = pl.data.elem_type },1397 .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
1048 };1398 };
1049 return initPayload(new_pl);1399 return initPayload(new_pl);
1050 },1400 },
10511401
1052 .fwd_struct,1402 .fwd_anon_struct,
1053 .fwd_union,1403 .fwd_anon_union,
1054 => {1404 => {
1055 const pl = self.cast(Payload.FwdDecl).?;1405 const pl = self.cast(Payload.Fields).?;
1056 const new_pl = try arena.create(Payload.FwdDecl);1406 const new_pl = try ctx.arena.create(Payload.Fields);
1057 new_pl.* = .{1407 new_pl.* = .{
1058 .base = .{ .tag = pl.base.tag },1408 .base = .{ .tag = pl.base.tag },
1059 .data = pl.data,1409 .data = try copyFields(ctx, pl.data),
1060 };1410 };
1061 return initPayload(new_pl);1411 return initPayload(new_pl);
1062 },1412 },
10631413
1064 .anon_struct,1414 .fwd_struct,
1065 .packed_anon_struct,1415 .fwd_union,
1066 => {1416 => {
1067 const pl = self.cast(Payload.Fields).?;1417 const pl = self.cast(Payload.FwdDecl).?;
1068 const new_pl = try arena.create(Payload.Fields);1418 const new_pl = try ctx.arena.create(Payload.FwdDecl);
1069 new_pl.* = .{1419 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
1070 .base = .{ .tag = pl.base.tag },1420 return initPayload(new_pl);
1071 .data = try copyFields(arena, pl.data),1421 },
1072 };1422
1423 .unnamed_struct,
1424 .unnamed_union,
1425 .packed_unnamed_struct,
1426 .packed_unnamed_union,
1427 => {
1428 const pl = self.cast(Payload.Unnamed).?;
1429 const new_pl = try ctx.arena.create(Payload.Unnamed);
1430 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1431 .fields = try copyFields(ctx, pl.data.fields),
1432 .owner_decl = pl.data.owner_decl,
1433 .id = pl.data.id,
1434 } };
1073 return initPayload(new_pl);1435 return initPayload(new_pl);
1074 },1436 },
10751437
1438 .anon_struct,
1439 .anon_union,
1076 .@"struct",1440 .@"struct",
1077 .@"union",1441 .@"union",
1078 .packed_struct,1442 .packed_struct,
1079 .packed_union,1443 .packed_union,
1080 => {1444 => {
1081 const pl = self.cast(Payload.Aggregate).?;1445 const pl = self.cast(Payload.Aggregate).?;
1082 const new_pl = try arena.create(Payload.Aggregate);1446 const new_pl = try ctx.arena.create(Payload.Aggregate);
1083 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{1447 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1084 .fields = try copyFields(arena, pl.data.fields),1448 .fields = try copyFields(ctx, pl.data.fields),
1085 .fwd_decl = pl.data.fwd_decl,1449 .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
1086 } };1450 } };
1087 return initPayload(new_pl);1451 return initPayload(new_pl);
1088 },1452 },
...@@ -1091,10 +1455,10 @@ pub const CType = extern union {...@@ -1091,10 +1455,10 @@ pub const CType = extern union {
1091 .varargs_function,1455 .varargs_function,
1092 => {1456 => {
1093 const pl = self.cast(Payload.Function).?;1457 const pl = self.cast(Payload.Function).?;
1094 const new_pl = try arena.create(Payload.Function);1458 const new_pl = try ctx.arena.create(Payload.Function);
1095 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{1459 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1096 .return_type = pl.data.return_type,1460 .return_type = ctx.copyIndex(pl.data.return_type),
1097 .param_types = try arena.dupe(Index, pl.data.param_types),1461 .param_types = try copyParams(ctx, pl.data.param_types),
1098 } };1462 } };
1099 return initPayload(new_pl);1463 return initPayload(new_pl);
1100 },1464 },
...@@ -1118,8 +1482,14 @@ pub const CType = extern union {...@@ -1118,8 +1482,14 @@ pub const CType = extern union {
1118 switch (convert.value) {1482 switch (convert.value) {
1119 .cty => |c| return c.copy(arena),1483 .cty => |c| return c.copy(arena),
1120 .tag => |t| switch (t) {1484 .tag => |t| switch (t) {
1485 .fwd_anon_struct,
1486 .fwd_anon_union,
1487 .unnamed_struct,
1488 .unnamed_union,
1489 .packed_unnamed_struct,
1490 .packed_unnamed_union,
1121 .anon_struct,1491 .anon_struct,
1122 .packed_anon_struct,1492 .anon_union,
1123 .@"struct",1493 .@"struct",
1124 .@"union",1494 .@"union",
1125 .packed_struct,1495 .packed_struct,
...@@ -1149,31 +1519,44 @@ pub const CType = extern union {...@@ -1149,31 +1519,44 @@ pub const CType = extern union {
1149 else1519 else
1150 arena.dupeZ(u8, ty.structFieldName(field_i)),1520 arena.dupeZ(u8, ty.structFieldName(field_i)),
1151 .type = store.set.typeToIndex(field_ty, target, switch (kind) {1521 .type = store.set.typeToIndex(field_ty, target, switch (kind) {
1152 .forward, .complete, .parameter => .complete,1522 .forward, .forward_parameter => .forward,
1523 .complete, .parameter => .complete,
1153 .global => .global,1524 .global => .global,
1525 .payload => unreachable,
1154 }).?,1526 }).?,
1155 .alignas = ty.structFieldAlign(field_i, target),1527 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1156 };1528 };
1157 c_field_i += 1;1529 c_field_i += 1;
1158 }1530 }
11591531
1160 if (ty.isTupleOrAnonStruct()) {1532 switch (t) {
1161 const anon_pl = try arena.create(Payload.Fields);1533 .fwd_anon_struct => {
1162 anon_pl.* = .{ .base = .{ .tag = .anon_struct }, .data = fields_pl };1534 const anon_pl = try arena.create(Payload.Fields);
1163 return initPayload(anon_pl);1535 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
1164 }1536 return initPayload(anon_pl);
1537 },
11651538
1166 const struct_pl = try arena.create(Payload.Aggregate);1539 .anon_struct,
1167 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{1540 .@"struct",
1168 .fields = fields_pl,1541 .@"union",
1169 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,1542 .packed_struct,
1170 } };1543 .packed_union,
1171 return initPayload(struct_pl);1544 => {
1545 const struct_pl = try arena.create(Payload.Aggregate);
1546 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1547 .fields = fields_pl,
1548 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1549 } };
1550 return initPayload(struct_pl);
1551 },
1552
1553 else => unreachable,
1554 }
1172 },1555 },
11731556
1174 .Union => {1557 .Union => {
1175 const fields = ty.unionFields();1558 const union_fields = ty.unionFields();
1176 const fields_len = fields.count();1559 const fields_len = union_fields.count();
11771560
1178 var c_fields_len: usize = 0;1561 var c_fields_len: usize = 0;
1179 for (0..fields_len) |field_i| {1562 for (0..fields_len) |field_i| {
...@@ -1185,7 +1568,7 @@ pub const CType = extern union {...@@ -1185,7 +1568,7 @@ pub const CType = extern union {
1185 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);1568 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1186 var field_i: usize = 0;1569 var field_i: usize = 0;
1187 var c_field_i: usize = 0;1570 var c_field_i: usize = 0;
1188 var field_it = fields.iterator();1571 var field_it = union_fields.iterator();
1189 while (field_it.next()) |field| {1572 while (field_it.next()) |field| {
1190 defer field_i += 1;1573 defer field_i += 1;
1191 if (!field.value_ptr.ty.hasRuntimeBitsIgnoreComptime()) continue;1574 if (!field.value_ptr.ty.hasRuntimeBitsIgnoreComptime()) continue;
...@@ -1193,21 +1576,35 @@ pub const CType = extern union {...@@ -1193,21 +1576,35 @@ pub const CType = extern union {
1193 fields_pl[c_field_i] = .{1576 fields_pl[c_field_i] = .{
1194 .name = try arena.dupeZ(u8, field.key_ptr.*),1577 .name = try arena.dupeZ(u8, field.key_ptr.*),
1195 .type = store.set.typeToIndex(field.value_ptr.ty, target, switch (kind) {1578 .type = store.set.typeToIndex(field.value_ptr.ty, target, switch (kind) {
1196 .forward => unreachable,1579 .forward, .forward_parameter => unreachable,
1197 .complete, .parameter => .complete,1580 .complete, .parameter, .payload => .complete,
1198 .global => .global,1581 .global => .global,
1199 }).?,1582 }).?,
1200 .alignas = ty.structFieldAlign(field_i, target),1583 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1201 };1584 };
1202 c_field_i += 1;1585 c_field_i += 1;
1203 }1586 }
12041587
1205 const union_pl = try arena.create(Payload.Aggregate);1588 switch (kind) {
1206 union_pl.* = .{ .base = .{ .tag = t }, .data = .{1589 .forward, .forward_parameter => unreachable,
1207 .fields = fields_pl,1590 .complete, .parameter, .global => {
1208 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,1591 const union_pl = try arena.create(Payload.Aggregate);
1209 } };1592 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1210 return initPayload(union_pl);1593 .fields = fields_pl,
1594 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1595 } };
1596 return initPayload(union_pl);
1597 },
1598 .payload => if (ty.unionTagTypeSafety()) |_| {
1599 const union_pl = try arena.create(Payload.Unnamed);
1600 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1601 .fields = fields_pl,
1602 .owner_decl = ty.getOwnerDecl(),
1603 .id = 0,
1604 } };
1605 return initPayload(union_pl);
1606 } else unreachable,
1607 }
1211 },1608 },
12121609
1213 else => unreachable,1610 else => unreachable,
...@@ -1217,9 +1614,10 @@ pub const CType = extern union {...@@ -1217,9 +1614,10 @@ pub const CType = extern union {
1217 .varargs_function,1614 .varargs_function,
1218 => {1615 => {
1219 const info = ty.fnInfo();1616 const info = ty.fnInfo();
1220 const recurse_kind: Kind = switch (kind) {1617 const param_kind: Kind = switch (kind) {
1221 .forward => .forward,1618 .forward, .forward_parameter => .forward_parameter,
1222 .complete, .parameter, .global => unreachable,1619 .complete, .parameter, .global => .parameter,
1620 .payload => unreachable,
1223 };1621 };
12241622
1225 var c_params_len: usize = 0;1623 var c_params_len: usize = 0;
...@@ -1232,13 +1630,13 @@ pub const CType = extern union {...@@ -1232,13 +1630,13 @@ pub const CType = extern union {
1232 var c_param_i: usize = 0;1630 var c_param_i: usize = 0;
1233 for (info.param_types) |param_type| {1631 for (info.param_types) |param_type| {
1234 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1632 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1235 params_pl[c_param_i] = store.set.typeToIndex(param_type, target, recurse_kind).?;1633 params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?;
1236 c_param_i += 1;1634 c_param_i += 1;
1237 }1635 }
12381636
1239 const fn_pl = try arena.create(Payload.Function);1637 const fn_pl = try arena.create(Payload.Function);
1240 fn_pl.* = .{ .base = .{ .tag = t }, .data = .{1638 fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
1241 .return_type = store.set.typeToIndex(info.return_type, target, recurse_kind).?,1639 .return_type = store.set.typeToIndex(info.return_type, target, param_kind).?,
1242 .param_types = params_pl,1640 .param_types = params_pl,
1243 } };1641 } };
1244 return initPayload(fn_pl);1642 return initPayload(fn_pl);
...@@ -1294,8 +1692,8 @@ pub const CType = extern union {...@@ -1294,8 +1692,8 @@ pub const CType = extern union {
12941692
1295 const target = self.lookup.getTarget();1693 const target = self.lookup.getTarget();
1296 switch (t) {1694 switch (t) {
1297 .anon_struct,1695 .fwd_anon_struct,
1298 .packed_anon_struct,1696 .fwd_anon_union,
1299 => {1697 => {
1300 if (!ty.isTupleOrAnonStruct()) return false;1698 if (!ty.isTupleOrAnonStruct()) return false;
13011699
...@@ -1313,26 +1711,38 @@ pub const CType = extern union {...@@ -1313,26 +1711,38 @@ pub const CType = extern union {
1313 const c_field = &c_fields[c_field_i];1711 const c_field = &c_fields[c_field_i];
1314 c_field_i += 1;1712 c_field_i += 1;
13151713
1316 if (!self.eqlRecurse(1714 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
1317 ty.structFieldType(field_i),1715 .forward, .forward_parameter => .forward,
1318 c_field.type,1716 .complete, .parameter => .complete,
1319 switch (self.kind) {1717 .global => .global,
1320 .forward, .complete, .parameter => .complete,1718 .payload => unreachable,
1321 .global => .global,1719 }) or !mem.eql(
1322 },
1323 ) or !mem.eql(
1324 u8,1720 u8,
1325 if (ty.isSimpleTuple())1721 if (ty.isSimpleTuple())
1326 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable1722 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1327 else1723 else
1328 ty.structFieldName(field_i),1724 ty.structFieldName(field_i),
1329 mem.span(c_field.name),1725 mem.span(c_field.name),
1330 ) or ty.structFieldAlign(field_i, target) != c_field.alignas)1726 ) or Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align" !=
1331 return false;1727 c_field.alignas.@"align") return false;
1332 }1728 }
1333 return true;1729 return true;
1334 },1730 },
13351731
1732 .unnamed_struct,
1733 .unnamed_union,
1734 .packed_unnamed_struct,
1735 .packed_unnamed_union,
1736 => switch (self.kind) {
1737 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1738 .payload => if (ty.unionTagTypeSafety()) |_| {
1739 const data = cty.cast(Payload.Unnamed).?.data;
1740 return ty.getOwnerDecl() == data.owner_decl and data.id == 0;
1741 } else unreachable,
1742 },
1743
1744 .anon_struct,
1745 .anon_union,
1336 .@"struct",1746 .@"struct",
1337 .@"union",1747 .@"union",
1338 .packed_struct,1748 .packed_struct,
...@@ -1350,19 +1760,27 @@ pub const CType = extern union {...@@ -1350,19 +1760,27 @@ pub const CType = extern union {
13501760
1351 const info = ty.fnInfo();1761 const info = ty.fnInfo();
1352 const data = cty.cast(Payload.Function).?.data;1762 const data = cty.cast(Payload.Function).?.data;
1353 const recurse_kind: Kind = switch (self.kind) {1763 const param_kind: Kind = switch (self.kind) {
1354 .forward => .forward,1764 .forward, .forward_parameter => .forward_parameter,
1355 .complete, .parameter, .global => unreachable,1765 .complete, .parameter, .global => .parameter,
1766 .payload => unreachable,
1356 };1767 };
13571768
1358 if (info.param_types.len != data.param_types.len or1769 if (!self.eqlRecurse(info.return_type, data.return_type, param_kind))
1359 !self.eqlRecurse(info.return_type, data.return_type, recurse_kind))
1360 return false;1770 return false;
1361 for (info.param_types, data.param_types) |param_ty, param_cty| {1771
1362 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;1772 var c_param_i: usize = 0;
1363 if (!self.eqlRecurse(param_ty, param_cty, recurse_kind)) return false;1773 for (info.param_types) |param_type| {
1774 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1775
1776 if (c_param_i >= data.param_types.len) return false;
1777 const param_cty = data.param_types[c_param_i];
1778 c_param_i += 1;
1779
1780 if (!self.eqlRecurse(param_type, param_cty, param_kind))
1781 return false;
1364 }1782 }
1365 return true;1783 return c_param_i == data.param_types.len;
1366 },1784 },
13671785
1368 else => unreachable,1786 else => unreachable,
...@@ -1395,13 +1813,17 @@ pub const CType = extern union {...@@ -1395,13 +1813,17 @@ pub const CType = extern union {
13951813
1396 const target = self.lookup.getTarget();1814 const target = self.lookup.getTarget();
1397 switch (t) {1815 switch (t) {
1398 .anon_struct,1816 .fwd_anon_struct,
1399 .packed_anon_struct,1817 .fwd_anon_union,
1400 => {1818 => {
1401 var name_buf: [1819 var name_buf: [
1402 std.fmt.count("f{}", .{std.math.maxInt(usize)})1820 std.fmt.count("f{}", .{std.math.maxInt(usize)})
1403 ]u8 = undefined;1821 ]u8 = undefined;
1404 for (0..ty.structFieldCount()) |field_i| {1822 for (0..switch (ty.zigTypeTag()) {
1823 .Struct => ty.structFieldCount(),
1824 .Union => ty.unionFields().count(),
1825 else => unreachable,
1826 }) |field_i| {
1405 const field_ty = ty.structFieldType(field_i);1827 const field_ty = ty.structFieldType(field_i);
1406 if (ty.structFieldIsComptime(field_i) or1828 if (ty.structFieldIsComptime(field_i) or
1407 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;1829 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
...@@ -1410,18 +1832,37 @@ pub const CType = extern union {...@@ -1410,18 +1832,37 @@ pub const CType = extern union {
1410 hasher,1832 hasher,
1411 ty.structFieldType(field_i),1833 ty.structFieldType(field_i),
1412 switch (self.kind) {1834 switch (self.kind) {
1413 .forward, .complete, .parameter => .complete,1835 .forward, .forward_parameter => .forward,
1836 .complete, .parameter => .complete,
1414 .global => .global,1837 .global => .global,
1838 .payload => unreachable,
1415 },1839 },
1416 );1840 );
1417 hasher.update(if (ty.isSimpleTuple())1841 hasher.update(if (ty.isSimpleTuple())
1418 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable1842 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1419 else1843 else
1420 ty.structFieldName(field_i));1844 ty.structFieldName(field_i));
1421 autoHash(hasher, ty.structFieldAlign(field_i, target));1845 autoHash(
1846 hasher,
1847 Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align",
1848 );
1422 }1849 }
1423 },1850 },
14241851
1852 .unnamed_struct,
1853 .unnamed_union,
1854 .packed_unnamed_struct,
1855 .packed_unnamed_union,
1856 => switch (self.kind) {
1857 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1858 .payload => if (ty.unionTagTypeSafety()) |_| {
1859 autoHash(hasher, ty.getOwnerDecl());
1860 autoHash(hasher, @as(u32, 0));
1861 } else unreachable,
1862 },
1863
1864 .anon_struct,
1865 .anon_union,
1425 .@"struct",1866 .@"struct",
1426 .@"union",1867 .@"union",
1427 .packed_struct,1868 .packed_struct,
...@@ -1432,15 +1873,16 @@ pub const CType = extern union {...@@ -1432,15 +1873,16 @@ pub const CType = extern union {
1432 .varargs_function,1873 .varargs_function,
1433 => {1874 => {
1434 const info = ty.fnInfo();1875 const info = ty.fnInfo();
1435 const recurse_kind: Kind = switch (self.kind) {1876 const param_kind: Kind = switch (self.kind) {
1436 .forward => .forward,1877 .forward, .forward_parameter => .forward_parameter,
1437 .complete, .parameter, .global => unreachable,1878 .complete, .parameter, .global => .parameter,
1879 .payload => unreachable,
1438 };1880 };
14391881
1440 self.updateHasherRecurse(hasher, info.return_type, recurse_kind);1882 self.updateHasherRecurse(hasher, info.return_type, param_kind);
1441 for (info.param_types) |param_type| {1883 for (info.param_types) |param_type| {
1442 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1884 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1443 self.updateHasherRecurse(hasher, param_type, recurse_kind);1885 self.updateHasherRecurse(hasher, param_type, param_kind);
1444 }1886 }
1445 },1887 },
14461888
src/link/C.zig+137-50
...@@ -117,7 +117,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes...@@ -117,7 +117,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
117 .gpa = gpa,117 .gpa = gpa,
118 .module = module,118 .module = module,
119 .error_msg = null,119 .error_msg = null,
120 .decl_index = decl_index,120 .decl_index = decl_index.toOptional(),
121 .decl = module.declPtr(decl_index),121 .decl = module.declPtr(decl_index),
122 .fwd_decl = fwd_decl.toManaged(gpa),122 .fwd_decl = fwd_decl.toManaged(gpa),
123 .ctypes = ctypes.*,123 .ctypes = ctypes.*,
...@@ -146,7 +146,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes...@@ -146,7 +146,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
146 code.* = function.object.code.moveToUnmanaged();146 code.* = function.object.code.moveToUnmanaged();
147147
148 // Free excess allocated memory for this Decl.148 // Free excess allocated memory for this Decl.
149 ctypes.shrinkToFit(gpa);149 ctypes.shrinkAndFree(gpa, ctypes.count());
150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
152 code.shrinkAndFree(gpa, code.items.len);152 code.shrinkAndFree(gpa, code.items.len);
...@@ -176,7 +176,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -176,7 +176,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
176 .gpa = gpa,176 .gpa = gpa,
177 .module = module,177 .module = module,
178 .error_msg = null,178 .error_msg = null,
179 .decl_index = decl_index,179 .decl_index = decl_index.toOptional(),
180 .decl = decl,180 .decl = decl,
181 .fwd_decl = fwd_decl.toManaged(gpa),181 .fwd_decl = fwd_decl.toManaged(gpa),
182 .ctypes = ctypes.*,182 .ctypes = ctypes.*,
...@@ -204,7 +204,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -204,7 +204,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
204 code.* = object.code.moveToUnmanaged();204 code.* = object.code.moveToUnmanaged();
205205
206 // Free excess allocated memory for this Decl.206 // Free excess allocated memory for this Decl.
207 ctypes.shrinkToFit(gpa);207 ctypes.shrinkAndFree(gpa, ctypes.count());
208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
209 code.shrinkAndFree(gpa, code.items.len);209 code.shrinkAndFree(gpa, code.items.len);
210}210}
...@@ -247,8 +247,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -247,8 +247,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
247247
248 const abi_define = abiDefine(comp);248 const abi_define = abiDefine(comp);
249249
250 // Covers defines, zig.h, ctypes, asm.250 // Covers defines, zig.h, ctypes, asm, lazy fwd, lazy code.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 4);251 try f.all_buffers.ensureUnusedCapacity(gpa, 6);
252252
253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
254 f.appendBufAssumeCapacity(zig_h);254 f.appendBufAssumeCapacity(zig_h);
...@@ -258,15 +258,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -258,15 +258,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
258258
259 {259 {
260 var asm_buf = f.asm_buf.toManaged(gpa);260 var asm_buf = f.asm_buf.toManaged(gpa);
261 defer asm_buf.deinit();261 defer f.asm_buf = asm_buf.moveToUnmanaged();
262262 try codegen.genGlobalAsm(module, asm_buf.writer());
263 try codegen.genGlobalAsm(module, &asm_buf);263 f.appendBufAssumeCapacity(asm_buf.items);
264
265 f.asm_buf = asm_buf.moveToUnmanaged();
266 f.appendBufAssumeCapacity(f.asm_buf.items);
267 }264 }
268265
269 try self.flushErrDecls(&f);266 const lazy_indices = f.all_buffers.items.len;
267 f.all_buffers.items.len += 2;
268
269 try self.flushErrDecls(&f.lazy_db);
270270
271 // `CType`s, forward decls, and non-functions first.271 // `CType`s, forward decls, and non-functions first.
272 // 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
...@@ -295,6 +295,30 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -295,6 +295,30 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
295 }295 }
296 }296 }
297297
298 {
299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
300 assert(f.ctypes.count() == 0);
301 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);
302
303 var it = self.decl_table.iterator();
304 while (it.next()) |entry|
305 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
306 }
307
308 {
309 f.all_buffers.items[lazy_indices + 0] = .{
310 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
311 .iov_len = f.lazy_db.fwd_decl.items.len,
312 };
313 f.file_size += f.lazy_db.fwd_decl.items.len;
314
315 f.all_buffers.items[lazy_indices + 1] = .{
316 .iov_base = if (f.lazy_db.code.items.len > 0) f.lazy_db.code.items.ptr else "",
317 .iov_len = f.lazy_db.code.items.len,
318 };
319 f.file_size += f.lazy_db.code.items.len;
320 }
321
298 f.all_buffers.items[ctypes_index] = .{322 f.all_buffers.items[ctypes_index] = .{
299 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",323 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
300 .iov_len = f.ctypes_buf.items.len,324 .iov_len = f.ctypes_buf.items.len,
...@@ -318,17 +342,17 @@ const Flush = struct {...@@ -318,17 +342,17 @@ const Flush = struct {
318 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},342 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
319 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},343 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
320344
321 err_decls: DeclBlock = .{},345 lazy_db: DeclBlock = .{},
322
323 lazy_fns: LazyFns = .{},346 lazy_fns: LazyFns = .{},
324347
325 asm_buf: std.ArrayListUnmanaged(u8) = .{},348 asm_buf: std.ArrayListUnmanaged(u8) = .{},
349
326 /// We collect a list of buffers to write, and write them all at once with pwritev 😎350 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
327 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},351 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
328 /// Keeps track of the total bytes of `all_buffers`.352 /// Keeps track of the total bytes of `all_buffers`.
329 file_size: u64 = 0,353 file_size: u64 = 0,
330354
331 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, DeclBlock);355 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
332356
333 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {357 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
334 if (buf.len == 0) return;358 if (buf.len == 0) return;
...@@ -338,10 +362,9 @@ const Flush = struct {...@@ -338,10 +362,9 @@ const Flush = struct {
338362
339 fn deinit(f: *Flush, gpa: Allocator) void {363 fn deinit(f: *Flush, gpa: Allocator) void {
340 f.all_buffers.deinit(gpa);364 f.all_buffers.deinit(gpa);
341 var lazy_fns_it = f.lazy_fns.valueIterator();365 f.asm_buf.deinit(gpa);
342 while (lazy_fns_it.next()) |db| db.deinit(gpa);
343 f.lazy_fns.deinit(gpa);366 f.lazy_fns.deinit(gpa);
344 f.err_decls.deinit(gpa);367 f.lazy_db.deinit(gpa);
345 f.ctypes_buf.deinit(gpa);368 f.ctypes_buf.deinit(gpa);
346 f.ctypes_map.deinit(gpa);369 f.ctypes_map.deinit(gpa);
347 f.ctypes.deinit(gpa);370 f.ctypes.deinit(gpa);
...@@ -353,26 +376,106 @@ const FlushDeclError = error{...@@ -353,26 +376,106 @@ const FlushDeclError = error{
353 OutOfMemory,376 OutOfMemory,
354};377};
355378
356fn flushCTypes(self: *C, f: *Flush, ctypes: codegen.CType.Store) FlushDeclError!void {379fn flushCTypes(
357 _ = self;380 self: *C,
358 _ = f;381 f: *Flush,
359 _ = ctypes;382 decl_index: Module.Decl.OptionalIndex,
383 decl_ctypes: codegen.CType.Store,
384) FlushDeclError!void {
385 const gpa = self.base.allocator;
386 const mod = self.base.options.module.?;
387
388 const decl_ctypes_len = decl_ctypes.count();
389 f.ctypes_map.clearRetainingCapacity();
390 try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);
391
392 var global_ctypes = f.ctypes.promote(gpa);
393 defer f.ctypes.demote(global_ctypes);
394
395 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
396 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
397 const writer = ctypes_buf.writer();
398
399 const slice = decl_ctypes.set.map.entries.slice();
400 for (slice.items(.key), 0..) |decl_cty, decl_i| {
401 const Context = struct {
402 arena: Allocator,
403 ctypes_map: []codegen.CType.Index,
404 cached_hash: codegen.CType.Store.Set.Map.Hash,
405 idx: codegen.CType.Index,
406
407 pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {
408 return ctx.cached_hash;
409 }
410 pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {
411 return lhs.eqlContext(rhs, ctx);
412 }
413 pub fn eqlIndex(
414 ctx: @This(),
415 lhs_idx: codegen.CType.Index,
416 rhs_idx: codegen.CType.Index,
417 ) bool {
418 if (lhs_idx < codegen.CType.Tag.no_payload_count or
419 rhs_idx < codegen.CType.Tag.no_payload_count) return lhs_idx == rhs_idx;
420 const lhs_i = lhs_idx - codegen.CType.Tag.no_payload_count;
421 if (lhs_i >= ctx.ctypes_map.len) return false;
422 return ctx.ctypes_map[lhs_i] == rhs_idx;
423 }
424 pub fn copyIndex(ctx: @This(), idx: codegen.CType.Index) codegen.CType.Index {
425 if (idx < codegen.CType.Tag.no_payload_count) return idx;
426 return ctx.ctypes_map[idx - codegen.CType.Tag.no_payload_count];
427 }
428 };
429 const decl_idx = @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + decl_i);
430 const ctx = Context{
431 .arena = global_ctypes.arena.allocator(),
432 .ctypes_map = f.ctypes_map.items,
433 .cached_hash = decl_ctypes.indexToHash(decl_idx),
434 .idx = decl_idx,
435 };
436 const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{
437 .store = &global_ctypes.set,
438 });
439 const global_idx =
440 @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + gop.index);
441 f.ctypes_map.appendAssumeCapacity(global_idx);
442 if (!gop.found_existing) {
443 errdefer _ = global_ctypes.set.map.pop();
444 gop.key_ptr.* = try decl_cty.copyContext(ctx);
445 }
446 if (std.debug.runtime_safety) {
447 const global_cty = &global_ctypes.set.map.entries.items(.key)[gop.index];
448 assert(global_cty == gop.key_ptr);
449 assert(decl_cty.eqlContext(global_cty.*, ctx));
450 assert(decl_cty.hash(decl_ctypes.set) == global_cty.hash(global_ctypes.set));
451 }
452 try codegen.genTypeDecl(
453 mod,
454 writer,
455 global_ctypes.set,
456 global_idx,
457 decl_index,
458 decl_ctypes.set,
459 decl_idx,
460 gop.found_existing,
461 );
462 }
360}463}
361464
362fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {465fn flushErrDecls(self: *C, db: *DeclBlock) FlushDeclError!void {
363 const gpa = self.base.allocator;466 const gpa = self.base.allocator;
364467
365 const fwd_decl = &f.err_decls.fwd_decl;468 const fwd_decl = &db.fwd_decl;
366 const ctypes = &f.err_decls.ctypes;469 const ctypes = &db.ctypes;
367 const code = &f.err_decls.code;470 const code = &db.code;
368471
369 var object = codegen.Object{472 var object = codegen.Object{
370 .dg = .{473 .dg = .{
371 .gpa = gpa,474 .gpa = gpa,
372 .module = self.base.options.module.?,475 .module = self.base.options.module.?,
373 .error_msg = null,476 .error_msg = null,
374 .decl_index = undefined,477 .decl_index = .none,
375 .decl = undefined,478 .decl = null,
376 .fwd_decl = fwd_decl.toManaged(gpa),479 .fwd_decl = fwd_decl.toManaged(gpa),
377 .ctypes = ctypes.*,480 .ctypes = ctypes.*,
378 },481 },
...@@ -394,19 +497,9 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {...@@ -394,19 +497,9 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
394 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();497 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
395 ctypes.* = object.dg.ctypes.move();498 ctypes.* = object.dg.ctypes.move();
396 code.* = object.code.moveToUnmanaged();499 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}500}
403501
404fn flushLazyFn(502fn flushLazyFn(self: *C, db: *DeclBlock, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void {
405 self: *C,
406 f: *Flush,
407 db: *DeclBlock,
408 lazy_fn: codegen.LazyFnMap.Entry,
409) FlushDeclError!void {
410 const gpa = self.base.allocator;503 const gpa = self.base.allocator;
411504
412 const fwd_decl = &db.fwd_decl;505 const fwd_decl = &db.fwd_decl;
...@@ -418,8 +511,8 @@ fn flushLazyFn(...@@ -418,8 +511,8 @@ fn flushLazyFn(
418 .gpa = gpa,511 .gpa = gpa,
419 .module = self.base.options.module.?,512 .module = self.base.options.module.?,
420 .error_msg = null,513 .error_msg = null,
421 .decl_index = undefined,514 .decl_index = .none,
422 .decl = undefined,515 .decl = null,
423 .fwd_decl = fwd_decl.toManaged(gpa),516 .fwd_decl = fwd_decl.toManaged(gpa),
424 .ctypes = ctypes.*,517 .ctypes = ctypes.*,
425 },518 },
...@@ -441,11 +534,6 @@ fn flushLazyFn(...@@ -441,11 +534,6 @@ fn flushLazyFn(
441 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();534 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
442 ctypes.* = object.dg.ctypes.move();535 ctypes.* = object.dg.ctypes.move();
443 code.* = object.code.moveToUnmanaged();536 code.* = object.code.moveToUnmanaged();
444
445 try self.flushCTypes(f, ctypes.*);
446 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
447 f.appendBufAssumeCapacity(fwd_decl.items);
448 f.appendBufAssumeCapacity(code.items);
449}537}
450538
451fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {539fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
...@@ -456,8 +544,8 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError...@@ -456,8 +544,8 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError
456 while (it.next()) |entry| {544 while (it.next()) |entry| {
457 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);545 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
458 if (gop.found_existing) continue;546 if (gop.found_existing) continue;
459 gop.value_ptr.* = .{};547 gop.value_ptr.* = {};
460 try self.flushLazyFn(f, gop.value_ptr, entry);548 try self.flushLazyFn(&f.lazy_db, entry);
461 }549 }
462}550}
463551
...@@ -481,7 +569,6 @@ fn flushDecl(...@@ -481,7 +569,6 @@ fn flushDecl(
481569
482 const decl_block = self.decl_table.getPtr(decl_index).?;570 const decl_block = self.decl_table.getPtr(decl_index).?;
483571
484 try self.flushCTypes(f, decl_block.ctypes);
485 try self.flushLazyFns(f, decl_block.lazy_fns);572 try self.flushLazyFns(f, decl_block.lazy_fns);
486 try f.all_buffers.ensureUnusedCapacity(gpa, 1);573 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
487 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))574 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))