authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 05:16:23-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 10:54:26-05:00
loga0d7fd162b7568c0291ebcfc561a2852c7077e15
tree476a76289e5e5a3b25631d2d15e21a704189ead5
parent57f6adf85da58c0c91a036deaa614c30df010b78

CBE: support call attributes

* Support always_tail and never_tail/never_inline with a comptime callee using clang * Support never_inline using gcc * Support never_inline using msvc Unfortunately, can't enable behavior tests because of the conditional support.

4 files changed, 304 insertions(+), 254 deletions(-)

lib/zig.h+26
...@@ -78,6 +78,32 @@ typedef char bool;...@@ -78,6 +78,32 @@ typedef char bool;
78#define zig_cold78#define zig_cold
79#endif79#endif
8080
81#if zig_has_attribute(flatten)
82#define zig_maybe_flatten __attribute__((flatten))
83#else
84#define zig_maybe_flatten
85#endif
86
87#if zig_has_attribute(noinline)
88#define zig_never_inline __attribute__((noinline)) zig_maybe_flatten
89#elif defined(_MSC_VER)
90#define zig_never_inline __declspec(noinline) zig_maybe_flatten
91#else
92#define zig_never_inline zig_never_inline_unavailable
93#endif
94
95#if zig_has_attribute(not_tail_called)
96#define zig_never_tail __attribute__((not_tail_called)) zig_never_inline
97#else
98#define zig_never_tail zig_never_tail_unavailable
99#endif
100
101#if zig_has_attribute(always_inline)
102#define zig_always_tail __attribute__((musttail))
103#else
104#define zig_always_tail zig_always_tail_unavailable
105#endif
106
81#if __STDC_VERSION__ >= 199901L107#if __STDC_VERSION__ >= 199901L
82#define zig_restrict restrict108#define zig_restrict restrict
83#elif defined(__GNUC__)109#elif defined(__GNUC__)
src/codegen/c.zig+263-233
...@@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix;...@@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { @"const", mut };
27const BigIntLimb = std.math.big.Limb;26const BigIntLimb = std.math.big.Limb;
28const BigInt = std.math.big.int;27const BigInt = std.math.big.int;
2928
...@@ -55,6 +54,8 @@ pub const CValue = union(enum) {...@@ -55,6 +54,8 @@ pub const CValue = union(enum) {
55 /// Render these bytes literally.54 /// Render these bytes literally.
56 /// TODO make this a [*:0]const u8 to save memory55 /// TODO make this a [*:0]const u8 to save memory
57 bytes: []const u8,56 bytes: []const u8,
57 /// A deferred call_always_tail
58 call_always_tail: void,
58};59};
5960
60const BlockData = struct {61const BlockData = struct {
...@@ -62,21 +63,22 @@ const BlockData = struct {...@@ -62,21 +63,22 @@ const BlockData = struct {
62 result: CValue,63 result: CValue,
63};64};
6465
65const TypedefKind = enum {
66 Forward,
67 Complete,
68};
69
70pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);66pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
7167
72pub const LazyFnKey = union(enum) {68pub const LazyFnKey = union(enum) {
73 tag_name: Decl.Index,69 tag_name: Decl.Index,
70 never_tail: Decl.Index,
71 never_inline: Decl.Index,
74};72};
75pub const LazyFnValue = struct {73pub const LazyFnValue = struct {
76 fn_name: []const u8,74 fn_name: []const u8,
77 data: union {75 data: Data,
76
77 pub const Data = union {
78 tag_name: Type,78 tag_name: Type,
79 },79 never_tail: void,
80 never_inline: void,
81 };
80};82};
81pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);83pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
8284
...@@ -314,7 +316,7 @@ pub const Function = struct {...@@ -314,7 +316,7 @@ pub const Function = struct {
314 const gpa = f.object.dg.gpa;316 const gpa = f.object.dg.gpa;
315 try f.allocs.put(gpa, decl_c_value.new_local, true);317 try f.allocs.put(gpa, decl_c_value.new_local, true);
316 try writer.writeAll("static ");318 try writer.writeAll("static ");
317 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);319 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
318 try writer.writeAll(" = ");320 try writer.writeAll(" = ");
319 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);321 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
320 try writer.writeAll(";\n ");322 try writer.writeAll(";\n ");
...@@ -348,15 +350,13 @@ pub const Function = struct {...@@ -348,15 +350,13 @@ pub const Function = struct {
348 }350 }
349351
350 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {352 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
351 const result = try f.allocAlignedLocal(ty, .mut, 0);353 const result = try f.allocAlignedLocal(ty, .{}, 0);
352 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });354 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
353 return result;355 return result;
354 }356 }
355357
356 /// Only allocates the local; does not print anything.358 /// Only allocates the local; does not print anything.
357 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {359 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
358 _ = mutability;
359
360 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {360 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {
361 for (locals_list.items, 0..) |local_index, i| {361 for (locals_list.items, 0..) |local_index, i| {
362 const local = &f.locals.items[local_index];362 const local = &f.locals.items[local_index];
...@@ -451,11 +451,9 @@ pub const Function = struct {...@@ -451,11 +451,9 @@ pub const Function = struct {
451 return f.object.dg.fmtIntLiteral(ty, val);451 return f.object.dg.fmtIntLiteral(ty, val);
452 }452 }
453453
454 fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 {454 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
455 const gpa = f.object.dg.gpa;455 const gpa = f.object.dg.gpa;
456 const owner_decl = enum_ty.getOwnerDecl();456 const gop = try f.lazy_fns.getOrPut(gpa, key);
457
458 const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl });
459 if (!gop.found_existing) {457 if (!gop.found_existing) {
460 errdefer _ = f.lazy_fns.pop();458 errdefer _ = f.lazy_fns.pop();
461459
...@@ -464,11 +462,21 @@ pub const Function = struct {...@@ -464,11 +462,21 @@ pub const Function = struct {
464 const arena = promoted.arena.allocator();462 const arena = promoted.arena.allocator();
465463
466 gop.value_ptr.* = .{464 gop.value_ptr.* = .{
467 .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{465 .fn_name = switch (key) {
468 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),466 .tag_name,
469 @enumToInt(owner_decl),467 .never_tail,
470 }),468 .never_inline,
471 .data = .{ .tag_name = try enum_ty.copy(arena) },469 => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{
470 @tagName(key),
471 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
472 @enumToInt(owner_decl),
473 }),
474 },
475 .data = switch (key) {
476 .tag_name => .{ .tag_name = try data.tag_name.copy(arena) },
477 .never_tail => .{ .never_tail = data.never_tail },
478 .never_inline => .{ .never_inline = data.never_inline },
479 },
472 };480 };
473 }481 }
474 return gop.value_ptr.fn_name;482 return gop.value_ptr.fn_name;
...@@ -1457,24 +1465,31 @@ pub const DeclGen = struct {...@@ -1457,24 +1465,31 @@ pub const DeclGen = struct {
1457 }1465 }
1458 }1466 }
14591467
1460 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {1468 fn renderFunctionSignature(
1469 dg: *DeclGen,
1470 w: anytype,
1471 fn_decl_index: Decl.Index,
1472 kind: CType.Kind,
1473 name: union(enum) {
1474 export_index: u32,
1475 string: []const u8,
1476 },
1477 ) !void {
1461 const store = &dg.ctypes.set;1478 const store = &dg.ctypes.set;
1462 const module = dg.module;1479 const module = dg.module;
14631480
1464 const fn_ty = dg.decl.?.ty;1481 const fn_decl = module.declPtr(fn_decl_index);
1465 const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) {1482 const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind);
1466 .Forward => .forward,
1467 .Complete => .complete,
1468 });
14691483
1470 const fn_info = fn_ty.fnInfo();1484 const fn_info = fn_decl.ty.fnInfo();
1471 if (fn_info.cc == .Naked) {1485 if (fn_info.cc == .Naked) {
1472 switch (kind) {1486 switch (kind) {
1473 .Forward => try w.writeAll("zig_naked_decl "),1487 .forward => try w.writeAll("zig_naked_decl "),
1474 .Complete => try w.writeAll("zig_naked "),1488 .complete => try w.writeAll("zig_naked "),
1489 else => unreachable,
1475 }1490 }
1476 }1491 }
1477 if (dg.decl.?.val.castTag(.function)) |func_payload|1492 if (fn_decl.val.castTag(.function)) |func_payload|
1478 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");1493 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1479 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");1494 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");
14801495
...@@ -1485,7 +1500,7 @@ pub const DeclGen = struct {...@@ -1485,7 +1500,7 @@ pub const DeclGen = struct {
1485 w,1500 w,
1486 fn_cty_idx,1501 fn_cty_idx,
1487 .suffix,1502 .suffix,
1488 CQualifiers.init(.{}),1503 .{},
1489 );1504 );
1490 try w.print("{}", .{trailing});1505 try w.print("{}", .{trailing});
14911506
...@@ -1493,16 +1508,37 @@ pub const DeclGen = struct {...@@ -1493,16 +1508,37 @@ pub const DeclGen = struct {
1493 try w.print("zig_callconv({s}) ", .{call_conv});1508 try w.print("zig_callconv({s}) ", .{call_conv});
1494 }1509 }
14951510
1496 if (fn_info.alignment > 0 and kind == .Complete) {1511 switch (kind) {
1497 try w.print(" zig_align_fn({})", .{fn_info.alignment});1512 .forward => {},
1513 .complete => if (fn_info.alignment > 0)
1514 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1515 else => unreachable,
1498 }1516 }
14991517
1500 try dg.renderDeclName(w, dg.decl_index.unwrap().?, export_index);1518 switch (name) {
1519 .export_index => |export_index| try dg.renderDeclName(w, fn_decl_index, export_index),
1520 .string => |string| try w.writeAll(string),
1521 }
15011522
1502 try renderTypeSuffix(dg.decl_index, store.*, module, w, fn_cty_idx, .suffix);1523 try renderTypeSuffix(
1524 dg.decl_index,
1525 store.*,
1526 module,
1527 w,
1528 fn_cty_idx,
1529 .suffix,
1530 CQualifiers.init(.{ .@"const" = switch (kind) {
1531 .forward => false,
1532 .complete => true,
1533 else => unreachable,
1534 } }),
1535 );
15031536
1504 if (fn_info.alignment > 0 and kind == .Forward) {1537 switch (kind) {
1505 try w.print(" zig_align_fn({})", .{fn_info.alignment});1538 .forward => if (fn_info.alignment > 0)
1539 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1540 .complete => {},
1541 else => unreachable,
1506 }1542 }
1507 }1543 }
15081544
...@@ -1533,16 +1569,8 @@ pub const DeclGen = struct {...@@ -1533,16 +1569,8 @@ pub const DeclGen = struct {
1533 const store = &dg.ctypes.set;1569 const store = &dg.ctypes.set;
1534 const module = dg.module;1570 const module = dg.module;
1535 const idx = try dg.typeToIndex(t, .complete);1571 const idx = try dg.typeToIndex(t, .complete);
1536 _ = try renderTypePrefix(1572 _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1537 dg.decl_index,1573 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1538 store.*,
1539 module,
1540 w,
1541 idx,
1542 .suffix,
1543 CQualifiers.init(.{}),
1544 );
1545 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
1546 }1574 }
15471575
1548 const IntCastContext = union(enum) {1576 const IntCastContext = union(enum) {
...@@ -1655,9 +1683,9 @@ pub const DeclGen = struct {...@@ -1655,9 +1683,9 @@ pub const DeclGen = struct {
1655 w: anytype,1683 w: anytype,
1656 ty: Type,1684 ty: Type,
1657 name: CValue,1685 name: CValue,
1658 mutability: Mutability,1686 qualifiers: CQualifiers,
1659 alignment: u32,1687 alignment: u32,
1660 _: TypedefKind,1688 kind: CType.Kind,
1661 ) error{ OutOfMemory, AnalysisFail }!void {1689 ) error{ OutOfMemory, AnalysisFail }!void {
1662 const store = &dg.ctypes.set;1690 const store = &dg.ctypes.set;
1663 const module = dg.module;1691 const module = dg.module;
...@@ -1668,71 +1696,12 @@ pub const DeclGen = struct {...@@ -1668,71 +1696,12 @@ pub const DeclGen = struct {
1668 .gt => try w.print("zig_align({}) ", .{alignment}),1696 .gt => try w.print("zig_align({}) ", .{alignment}),
1669 };1697 };
16701698
1671 const idx = try dg.typeToIndex(ty, .complete);1699 const idx = try dg.typeToIndex(ty, kind);
1672 const trailing = try renderTypePrefix(1700 const trailing =
1673 dg.decl_index,1701 try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, qualifiers);
1674 store.*,
1675 module,
1676 w,
1677 idx,
1678 .suffix,
1679 CQualifiers.init(.{ .@"const" = mutability == .@"const" }),
1680 );
1681 try w.print("{}", .{trailing});1702 try w.print("{}", .{trailing});
1682 try dg.writeCValue(w, name);1703 try dg.writeCValue(w, name);
1683 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);1704 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1684 }
1685
1686 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
1687 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
1688
1689 try w.writeAll("static ");
1690 try dg.renderType(w, name_slice_ty);
1691 try w.writeByte(' ');
1692 try w.writeAll(fn_name);
1693 try w.writeByte('(');
1694 try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete);
1695 try w.writeAll(") {\n switch (tag) {\n");
1696 for (enum_ty.enumFields().keys(), 0..) |name, index| {
1697 const name_z = try dg.gpa.dupeZ(u8, name);
1698 defer dg.gpa.free(name_z);
1699 const name_bytes = name_z[0 .. name_z.len + 1];
1700
1701 var tag_pl: Value.Payload.U32 = .{
1702 .base = .{ .tag = .enum_field_index },
1703 .data = @intCast(u32, index),
1704 };
1705 const tag_val = Value.initPayload(&tag_pl.base);
1706
1707 var int_pl: Value.Payload.U64 = undefined;
1708 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
1709
1710 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
1711 const name_ty = Type.initPayload(&name_ty_pl.base);
1712
1713 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
1714 const name_val = Value.initPayload(&name_pl.base);
1715
1716 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
1717 const len_val = Value.initPayload(&len_pl.base);
1718
1719 try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
1720 try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete);
1721 try w.writeAll(" = ");
1722 try dg.renderValue(w, name_ty, name_val, .Initializer);
1723 try w.writeAll(";\n return (");
1724 try dg.renderType(w, name_slice_ty);
1725 try w.print("){{{}, {}}};\n", .{
1726 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
1727 });
1728
1729 try w.writeAll(" }\n");
1730 }
1731 try w.writeAll(" }\n while (");
1732 try dg.renderValue(w, Type.bool, Value.true, .Other);
1733 try w.writeAll(") ");
1734 _ = try airBreakpoint(w);
1735 try w.writeAll("}\n");
1736 }1705 }
17371706
1738 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {1707 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
...@@ -1771,6 +1740,7 @@ pub const DeclGen = struct {...@@ -1771,6 +1740,7 @@ pub const DeclGen = struct {
1771 fmtIdent(ident),1740 fmtIdent(ident),
1772 }),1741 }),
1773 .bytes => |bytes| return w.writeAll(bytes),1742 .bytes => |bytes| return w.writeAll(bytes),
1743 .call_always_tail => return dg.fail("CBE: the result of @call(.always_tail, ...) must be returned directly", .{}),
1774 }1744 }
1775 }1745 }
17761746
...@@ -1804,6 +1774,7 @@ pub const DeclGen = struct {...@@ -1804,6 +1774,7 @@ pub const DeclGen = struct {
1804 try w.writeAll(bytes);1774 try w.writeAll(bytes);
1805 return w.writeByte(')');1775 return w.writeByte(')');
1806 },1776 },
1777 .call_always_tail => return dg.writeCValue(w, c_value),
1807 }1778 }
1808 }1779 }
18091780
...@@ -1816,7 +1787,16 @@ pub const DeclGen = struct {...@@ -1816,7 +1787,16 @@ pub const DeclGen = struct {
1816 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {1787 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
1817 switch (c_value) {1788 switch (c_value) {
1818 .none, .constant, .field, .undef => unreachable,1789 .none, .constant, .field, .undef => unreachable,
1819 .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => {1790 .new_local,
1791 .local,
1792 .arg,
1793 .arg_array,
1794 .decl,
1795 .identifier,
1796 .payload_identifier,
1797 .bytes,
1798 .call_always_tail,
1799 => {
1820 try dg.writeCValue(writer, c_value);1800 try dg.writeCValue(writer, c_value);
1821 try writer.writeAll("->");1801 try writer.writeAll("->");
1822 },1802 },
...@@ -1945,7 +1925,8 @@ pub const DeclGen = struct {...@@ -1945,7 +1925,8 @@ pub const DeclGen = struct {
19451925
1946const CTypeFix = enum { prefix, suffix };1926const CTypeFix = enum { prefix, suffix };
1947const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });1927const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1948const CTypeRenderTrailing = enum {1928const Const = CQualifiers.init(.{ .@"const" = true });
1929const RenderCTypeTrailing = enum {
1949 no_space,1930 no_space,
1950 maybe_space,1931 maybe_space,
19511932
...@@ -2004,8 +1985,8 @@ fn renderTypePrefix(...@@ -2004,8 +1985,8 @@ fn renderTypePrefix(
2004 idx: CType.Index,1985 idx: CType.Index,
2005 parent_fix: CTypeFix,1986 parent_fix: CTypeFix,
2006 qualifiers: CQualifiers,1987 qualifiers: CQualifiers,
2007) @TypeOf(w).Error!CTypeRenderTrailing {1988) @TypeOf(w).Error!RenderCTypeTrailing {
2008 var trailing = CTypeRenderTrailing.maybe_space;1989 var trailing = RenderCTypeTrailing.maybe_space;
20091990
2010 const cty = store.indexToCType(idx);1991 const cty = store.indexToCType(idx);
2011 switch (cty.tag()) {1992 switch (cty.tag()) {
...@@ -2147,7 +2128,7 @@ fn renderTypePrefix(...@@ -2147,7 +2128,7 @@ fn renderTypePrefix(
2147 w,2128 w,
2148 cty.cast(CType.Payload.Function).?.data.return_type,2129 cty.cast(CType.Payload.Function).?.data.return_type,
2149 .suffix,2130 .suffix,
2150 CQualifiers.init(.{}),2131 .{},
2151 );2132 );
2152 switch (parent_fix) {2133 switch (parent_fix) {
2153 .prefix => {2134 .prefix => {
...@@ -2174,6 +2155,7 @@ fn renderTypeSuffix(...@@ -2174,6 +2155,7 @@ fn renderTypeSuffix(
2174 w: anytype,2155 w: anytype,
2175 idx: CType.Index,2156 idx: CType.Index,
2176 parent_fix: CTypeFix,2157 parent_fix: CTypeFix,
2158 qualifiers: CQualifiers,
2177) @TypeOf(w).Error!void {2159) @TypeOf(w).Error!void {
2178 const cty = store.indexToCType(idx);2160 const cty = store.indexToCType(idx);
2179 switch (cty.tag()) {2161 switch (cty.tag()) {
...@@ -2220,7 +2202,15 @@ fn renderTypeSuffix(...@@ -2220,7 +2202,15 @@ fn renderTypeSuffix(
2220 .pointer_const,2202 .pointer_const,
2221 .pointer_volatile,2203 .pointer_volatile,
2222 .pointer_const_volatile,2204 .pointer_const_volatile,
2223 => try renderTypeSuffix(decl, store, mod, w, cty.cast(CType.Payload.Child).?.data, .prefix),2205 => try renderTypeSuffix(
2206 decl,
2207 store,
2208 mod,
2209 w,
2210 cty.cast(CType.Payload.Child).?.data,
2211 .prefix,
2212 .{},
2213 ),
22242214
2225 .array,2215 .array,
2226 .vector,2216 .vector,
...@@ -2238,6 +2228,7 @@ fn renderTypeSuffix(...@@ -2238,6 +2228,7 @@ fn renderTypeSuffix(
2238 w,2228 w,
2239 cty.cast(CType.Payload.Sequence).?.data.elem_type,2229 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2240 .suffix,2230 .suffix,
2231 .{},
2241 );2232 );
2242 },2233 },
22432234
...@@ -2272,17 +2263,10 @@ fn renderTypeSuffix(...@@ -2272,17 +2263,10 @@ fn renderTypeSuffix(
2272 for (data.param_types, 0..) |param_type, param_i| {2263 for (data.param_types, 0..) |param_type, param_i| {
2273 if (need_comma) try w.writeAll(", ");2264 if (need_comma) try w.writeAll(", ");
2274 need_comma = true;2265 need_comma = true;
2275 const trailing = try renderTypePrefix(2266 const trailing =
2276 decl,2267 try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers);
2277 store,2268 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
2278 mod,2269 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{});
2279 w,
2280 param_type,
2281 .suffix,
2282 CQualifiers.init(.{ .@"const" = true }),
2283 );
2284 try w.print("{}a{d}", .{ trailing, param_i });
2285 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix);
2286 }2270 }
2287 switch (tag) {2271 switch (tag) {
2288 .function => {},2272 .function => {},
...@@ -2296,7 +2280,7 @@ fn renderTypeSuffix(...@@ -2296,7 +2280,7 @@ fn renderTypeSuffix(
2296 if (!need_comma) try w.writeAll("void");2280 if (!need_comma) try w.writeAll("void");
2297 try w.writeByte(')');2281 try w.writeByte(')');
22982282
2299 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix);2283 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix, .{});
2300 },2284 },
2301 }2285 }
2302}2286}
...@@ -2316,17 +2300,9 @@ fn renderAggregateFields(...@@ -2316,17 +2300,9 @@ fn renderAggregateFields(
2316 .eq => {},2300 .eq => {},
2317 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),2301 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
2318 }2302 }
2319 const trailing = try renderTypePrefix(2303 const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{});
2320 .none,
2321 store,
2322 mod,
2323 writer,
2324 field.type,
2325 .suffix,
2326 CQualifiers.init(.{}),
2327 );
2328 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });2304 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2329 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix);2305 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix, .{});
2330 try writer.writeAll(";\n");2306 try writer.writeAll(";\n");
2331 }2307 }
2332 try writer.writeByteNTimes(' ', indent);2308 try writer.writeByteNTimes(' ', indent);
...@@ -2347,25 +2323,9 @@ pub fn genTypeDecl(...@@ -2347,25 +2323,9 @@ pub fn genTypeDecl(
2347 switch (global_cty.tag()) {2323 switch (global_cty.tag()) {
2348 .fwd_anon_struct => if (decl != .none) {2324 .fwd_anon_struct => if (decl != .none) {
2349 try writer.writeAll("typedef ");2325 try writer.writeAll("typedef ");
2350 _ = try renderTypePrefix(2326 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2351 .none,
2352 global_store,
2353 mod,
2354 writer,
2355 global_idx,
2356 .suffix,
2357 CQualifiers.init(.{}),
2358 );
2359 try writer.writeByte(' ');2327 try writer.writeByte(' ');
2360 _ = try renderTypePrefix(2328 _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{});
2361 decl,
2362 decl_store,
2363 mod,
2364 writer,
2365 decl_idx,
2366 .suffix,
2367 CQualifiers.init(.{}),
2368 );
2369 try writer.writeAll(";\n");2329 try writer.writeAll(";\n");
2370 },2330 },
23712331
...@@ -2383,15 +2343,7 @@ pub fn genTypeDecl(...@@ -2383,15 +2343,7 @@ pub fn genTypeDecl(
2383 .fwd_union,2343 .fwd_union,
2384 => {2344 => {
2385 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;2345 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2386 _ = try renderTypePrefix(2346 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2387 .none,
2388 global_store,
2389 mod,
2390 writer,
2391 global_idx,
2392 .suffix,
2393 CQualifiers.init(.{}),
2394 );
2395 try writer.writeAll("; // ");2347 try writer.writeAll("; // ");
2396 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);2348 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
2397 try writer.writeByte('\n');2349 try writer.writeByte('\n');
...@@ -2467,7 +2419,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2467,7 +2419,7 @@ pub fn genErrDecls(o: *Object) !void {
2467 const name_val = Value.initPayload(&name_pl.base);2419 const name_val = Value.initPayload(&name_pl.base);
24682420
2469 try writer.writeAll("static ");2421 try writer.writeAll("static ");
2470 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .@"const", 0, .Complete);2422 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete);
2471 try writer.writeAll(" = ");2423 try writer.writeAll(" = ");
2472 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);2424 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
2473 try writer.writeAll(";\n");2425 try writer.writeAll(";\n");
...@@ -2480,7 +2432,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2480,7 +2432,7 @@ pub fn genErrDecls(o: *Object) !void {
2480 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);2432 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
24812433
2482 try writer.writeAll("static ");2434 try writer.writeAll("static ");
2483 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .@"const", 0, .Complete);2435 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, Const, 0, .complete);
2484 try writer.writeAll(" = {");2436 try writer.writeAll(" = {");
2485 for (o.dg.module.error_name_list.items, 0..) |name, value| {2437 for (o.dg.module.error_name_list.items, 0..) |name, value| {
2486 if (value != 0) try writer.writeByte(',');2438 if (value != 0) try writer.writeByte(',');
...@@ -2503,7 +2455,7 @@ fn genExports(o: *Object) !void {...@@ -2503,7 +2455,7 @@ fn genExports(o: *Object) !void {
2503 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {2455 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
2504 for (exports.items[1..], 1..) |@"export", i| {2456 for (exports.items[1..], 1..) |@"export", i| {
2505 try fwd_decl_writer.writeAll("zig_export(");2457 try fwd_decl_writer.writeAll("zig_export(");
2506 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, i));2458 try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) });
2507 try fwd_decl_writer.print(", {s}, {s});\n", .{2459 try fwd_decl_writer.print(", {s}, {s});\n", .{
2508 fmtStringLiteral(exports.items[0].options.name),2460 fmtStringLiteral(exports.items[0].options.name),
2509 fmtStringLiteral(@"export".options.name),2461 fmtStringLiteral(@"export".options.name),
...@@ -2513,13 +2465,85 @@ fn genExports(o: *Object) !void {...@@ -2513,13 +2465,85 @@ fn genExports(o: *Object) !void {
2513}2465}
25142466
2515pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {2467pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2516 const writer = o.writer();2468 const w = o.writer();
2517 switch (lazy_fn.key_ptr.*) {2469 const key = lazy_fn.key_ptr.*;
2518 .tag_name => _ = try o.dg.renderTagNameFn(2470 const val = lazy_fn.value_ptr;
2519 writer,2471 const fn_name = val.fn_name;
2520 lazy_fn.value_ptr.fn_name,2472 switch (key) {
2521 lazy_fn.value_ptr.data.tag_name,2473 .tag_name => {
2522 ),2474 const enum_ty = val.data.tag_name;
2475
2476 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2477
2478 try w.writeAll("static ");
2479 try o.dg.renderType(w, name_slice_ty);
2480 try w.writeByte(' ');
2481 try w.writeAll(fn_name);
2482 try w.writeByte('(');
2483 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
2484 try w.writeAll(") {\n switch (tag) {\n");
2485 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2486 const name_z = try o.dg.gpa.dupeZ(u8, name);
2487 defer o.dg.gpa.free(name_z);
2488 const name_bytes = name_z[0 .. name_z.len + 1];
2489
2490 var tag_pl: Value.Payload.U32 = .{
2491 .base = .{ .tag = .enum_field_index },
2492 .data = @intCast(u32, index),
2493 };
2494 const tag_val = Value.initPayload(&tag_pl.base);
2495
2496 var int_pl: Value.Payload.U64 = undefined;
2497 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
2498
2499 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2500 const name_ty = Type.initPayload(&name_ty_pl.base);
2501
2502 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
2503 const name_val = Value.initPayload(&name_pl.base);
2504
2505 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2506 const len_val = Value.initPayload(&len_pl.base);
2507
2508 try w.print(" case {}: {{\n static ", .{try o.dg.fmtIntLiteral(enum_ty, int_val)});
2509 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete);
2510 try w.writeAll(" = ");
2511 try o.dg.renderValue(w, name_ty, name_val, .Initializer);
2512 try w.writeAll(";\n return (");
2513 try o.dg.renderType(w, name_slice_ty);
2514 try w.print("){{{}, {}}};\n", .{
2515 fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val),
2516 });
2517
2518 try w.writeAll(" }\n");
2519 }
2520 try w.writeAll(" }\n while (");
2521 try o.dg.renderValue(w, Type.bool, Value.true, .Other);
2522 try w.writeAll(") ");
2523 _ = try airBreakpoint(w);
2524 try w.writeAll("}\n");
2525 },
2526 .never_tail, .never_inline => |fn_decl_index| {
2527 const fn_decl = o.dg.module.declPtr(fn_decl_index);
2528 const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete);
2529 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
2530
2531 const fwd_decl_writer = o.dg.fwd_decl.writer();
2532 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2533 try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ .string = fn_name });
2534 try fwd_decl_writer.writeAll(";\n");
2535
2536 try w.print("static zig_{s} ", .{@tagName(key)});
2537 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .string = fn_name });
2538 try w.writeAll(" {\n return ");
2539 try o.dg.renderDeclName(w, fn_decl_index, 0);
2540 try w.writeByte('(');
2541 for (0..fn_info.param_types.len) |arg| {
2542 if (arg > 0) try w.writeAll(", ");
2543 try o.dg.writeCValue(w, .{ .arg = arg });
2544 }
2545 try w.writeAll(");\n}\n");
2546 },
2523 }2547 }
2524}2548}
25252549
...@@ -2529,6 +2553,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2529,6 +2553,7 @@ pub fn genFunc(f: *Function) !void {
25292553
2530 const o = &f.object;2554 const o = &f.object;
2531 const gpa = o.dg.gpa;2555 const gpa = o.dg.gpa;
2556 const decl_index = o.dg.decl_index.unwrap().?;
2532 const tv: TypedValue = .{2557 const tv: TypedValue = .{
2533 .ty = o.dg.decl.?.ty,2558 .ty = o.dg.decl.?.ty,
2534 .val = o.dg.decl.?.val,2559 .val = o.dg.decl.?.val,
...@@ -2540,13 +2565,13 @@ pub fn genFunc(f: *Function) !void {...@@ -2540,13 +2565,13 @@ pub fn genFunc(f: *Function) !void {
2540 const is_global = o.dg.declIsGlobal(tv);2565 const is_global = o.dg.declIsGlobal(tv);
2541 const fwd_decl_writer = o.dg.fwd_decl.writer();2566 const fwd_decl_writer = o.dg.fwd_decl.writer();
2542 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2567 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2543 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);2568 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
2544 try fwd_decl_writer.writeAll(";\n");2569 try fwd_decl_writer.writeAll(";\n");
2545 try genExports(o);2570 try genExports(o);
25462571
2547 try o.indent_writer.insertNewline();2572 try o.indent_writer.insertNewline();
2548 if (!is_global) try o.writer().writeAll("static ");2573 if (!is_global) try o.writer().writeAll("static ");
2549 try o.dg.renderFunctionSignature(o.writer(), .Complete, 0);2574 try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
2550 try o.writer().writeByte(' ');2575 try o.writer().writeByte(' ');
25512576
2552 // In case we need to use the header, populate it with a copy of the function2577 // In case we need to use the header, populate it with a copy of the function
...@@ -2600,9 +2625,9 @@ pub fn genFunc(f: *Function) !void {...@@ -2600,9 +2625,9 @@ pub fn genFunc(f: *Function) !void {
2600 w,2625 w,
2601 local.ty,2626 local.ty,
2602 .{ .local = local_index },2627 .{ .local = local_index },
2603 .mut,2628 .{},
2604 local.alignment,2629 local.alignment,
2605 .Complete,2630 .complete,
2606 );2631 );
2607 try w.writeAll(";\n ");2632 try w.writeAll(";\n ");
2608 }2633 }
...@@ -2628,7 +2653,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2628,7 +2653,7 @@ pub fn genDecl(o: *Object) !void {
2628 if (tv.val.tag() == .extern_fn) {2653 if (tv.val.tag() == .extern_fn) {
2629 const fwd_decl_writer = o.dg.fwd_decl.writer();2654 const fwd_decl_writer = o.dg.fwd_decl.writer();
2630 try fwd_decl_writer.writeAll("zig_extern ");2655 try fwd_decl_writer.writeAll("zig_extern ");
2631 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);2656 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 });
2632 try fwd_decl_writer.writeAll(";\n");2657 try fwd_decl_writer.writeAll(";\n");
2633 try genExports(o);2658 try genExports(o);
2634 } else if (tv.val.castTag(.variable)) |var_payload| {2659 } else if (tv.val.castTag(.variable)) |var_payload| {
...@@ -2639,7 +2664,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2639,7 +2664,7 @@ pub fn genDecl(o: *Object) !void {
26392664
2640 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2665 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2641 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");2666 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2642 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .mut, decl.@"align", .Complete);2667 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .{}, decl.@"align", .complete);
2643 try fwd_decl_writer.writeAll(";\n");2668 try fwd_decl_writer.writeAll(";\n");
2644 try genExports(o);2669 try genExports(o);
26452670
...@@ -2649,7 +2674,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2649,7 +2674,7 @@ pub fn genDecl(o: *Object) !void {
2649 if (!is_global) try w.writeAll("static ");2674 if (!is_global) try w.writeAll("static ");
2650 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2675 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2651 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2676 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2652 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .mut, decl.@"align", .Complete);2677 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete);
2653 if (decl.@"linksection" != null) try w.writeAll(", read, write)");2678 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
2654 try w.writeAll(" = ");2679 try w.writeAll(" = ");
2655 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);2680 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
...@@ -2660,13 +2685,13 @@ pub fn genDecl(o: *Object) !void {...@@ -2660,13 +2685,13 @@ pub fn genDecl(o: *Object) !void {
2660 const fwd_decl_writer = o.dg.fwd_decl.writer();2685 const fwd_decl_writer = o.dg.fwd_decl.writer();
26612686
2662 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2687 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2663 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);2688 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.@"align", .complete);
2664 try fwd_decl_writer.writeAll(";\n");2689 try fwd_decl_writer.writeAll(";\n");
26652690
2666 const w = o.writer();2691 const w = o.writer();
2667 if (!is_global) try w.writeAll("static ");2692 if (!is_global) try w.writeAll("static ");
2668 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2693 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2669 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);2694 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete);
2670 if (decl.@"linksection" != null) try w.writeAll(", read)");2695 if (decl.@"linksection" != null) try w.writeAll(", read)");
2671 try w.writeAll(" = ");2696 try w.writeAll(" = ");
2672 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2697 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
...@@ -2689,7 +2714,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2689,7 +2714,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2689 const is_global = dg.declIsGlobal(tv);2714 const is_global = dg.declIsGlobal(tv);
2690 if (is_global) {2715 if (is_global) {
2691 try writer.writeAll("zig_extern ");2716 try writer.writeAll("zig_extern ");
2692 try dg.renderFunctionSignature(writer, .Complete, 0);2717 try dg.renderFunctionSignature(writer, dg.decl_index.unwrap().?, .complete, .{ .export_index = 0 });
2693 try dg.fwd_decl.appendSlice(";\n");2718 try dg.fwd_decl.appendSlice(";\n");
2694 }2719 }
2695 },2720 },
...@@ -2879,10 +2904,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2879,10 +2904,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
28792904
2880 .dbg_block_begin,2905 .dbg_block_begin,
2881 .dbg_block_end,2906 .dbg_block_end,
2882 => CValue{ .none = {} },2907 => .none,
28832908
2884 .call => try airCall(f, inst, .auto),2909 .call => try airCall(f, inst, .auto),
2885 .call_always_tail => try airCall(f, inst, .always_tail),2910 .call_always_tail => .call_always_tail,
2886 .call_never_tail => try airCall(f, inst, .never_tail),2911 .call_never_tail => try airCall(f, inst, .never_tail),
2887 .call_never_inline => try airCall(f, inst, .never_inline),2912 .call_never_inline => try airCall(f, inst, .never_inline),
28882913
...@@ -3199,9 +3224,12 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3199,9 +3224,12 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3199 return CValue{ .undef = inst_ty };3224 return CValue{ .undef = inst_ty };
3200 }3225 }
32013226
3202 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3203 const target = f.object.dg.module.getTarget();3227 const target = f.object.dg.module.getTarget();
3204 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));3228 const local = try f.allocAlignedLocal(
3229 elem_type,
3230 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3231 inst_ty.ptrAlignment(target),
3232 );
3205 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3233 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3206 const gpa = f.object.dg.module.gpa;3234 const gpa = f.object.dg.module.gpa;
3207 try f.allocs.put(gpa, local.new_local, false);3235 try f.allocs.put(gpa, local.new_local, false);
...@@ -3216,9 +3244,12 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3216,9 +3244,12 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3216 return CValue{ .undef = inst_ty };3244 return CValue{ .undef = inst_ty };
3217 }3245 }
32183246
3219 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3220 const target = f.object.dg.module.getTarget();3247 const target = f.object.dg.module.getTarget();
3221 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));3248 const local = try f.allocAlignedLocal(
3249 elem_ty,
3250 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3251 inst_ty.ptrAlignment(target),
3252 );
3222 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3253 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3223 const gpa = f.object.dg.module.gpa;3254 const gpa = f.object.dg.module.gpa;
3224 try f.allocs.put(gpa, local.new_local, false);3255 try f.allocs.put(gpa, local.new_local, false);
...@@ -3336,10 +3367,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3336,10 +3367,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3336 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;3367 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3337 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);3368 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
33383369
3339 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {3370 const is_naked = if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() == .Naked else false;
3340 var deref = is_ptr;3371 const peek_operand = f.value_map.get(un_op);
3372 if (if (peek_operand) |operand| operand == .call_always_tail else false) {
3373 try reap(f, inst, &.{un_op});
3374 if (is_naked) {
3375 try f.writeCValue(writer, peek_operand.?, .Other);
3376 unreachable;
3377 }
3378 _ = try airCall(f, Air.refToIndex(un_op).?, .always_tail);
3379 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
3341 const operand = try f.resolveInst(un_op);3380 const operand = try f.resolveInst(un_op);
3342 try reap(f, inst, &.{un_op});3381 try reap(f, inst, &.{un_op});
3382 var deref = is_ptr;
3343 const is_array = lowersToArray(ret_ty, target);3383 const is_array = lowersToArray(ret_ty, target);
3344 const ret_val = if (is_array) ret_val: {3384 const ret_val = if (is_array) ret_val: {
3345 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));3385 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
...@@ -3368,9 +3408,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3368,9 +3408,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3368 }3408 }
3369 } else {3409 } else {
3370 try reap(f, inst, &.{un_op});3410 try reap(f, inst, &.{un_op});
3371 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked)3411 // Not even allowed to return void in a naked function.
3372 // Not even allowed to return void in a naked function.3412 if (!is_naked) try writer.writeAll("return;\n");
3373 try writer.writeAll("return;\n");
3374 }3413 }
3375 return CValue.none;3414 return CValue.none;
3376}3415}
...@@ -4004,13 +4043,6 @@ fn airCall(...@@ -4004,13 +4043,6 @@ fn airCall(
4004 const target = module.getTarget();4043 const target = module.getTarget();
4005 const writer = f.object.writer();4044 const writer = f.object.writer();
40064045
4007 switch (modifier) {
4008 .auto => {},
4009 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),
4010 .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}),
4011 .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}),
4012 else => unreachable,
4013 }
4014 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4046 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
4015 const extra = f.air.extraData(Air.Call, pl_op.payload);4047 const extra = f.air.extraData(Air.Call, pl_op.payload);
4016 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);4048 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
...@@ -4060,7 +4092,10 @@ fn airCall(...@@ -4060,7 +4092,10 @@ fn airCall(
4060 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;4092 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
4061 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);4093 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
40624094
4063 const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())4095 const result_local: CValue = if (modifier == .always_tail) r: {
4096 try writer.writeAll("zig_always_tail return ");
4097 break :r .none;
4098 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
4064 .none4099 .none
4065 else if (f.liveness.isUnused(inst)) r: {4100 else if (f.liveness.isUnused(inst)) r: {
4066 try writer.writeByte('(');4101 try writer.writeByte('(');
...@@ -4074,26 +4109,33 @@ fn airCall(...@@ -4074,26 +4109,33 @@ fn airCall(
4074 break :r local;4109 break :r local;
4075 };4110 };
40764111
4077 var is_extern = false;
4078 var name: [*:0]const u8 = "";
4079 callee: {4112 callee: {
4080 known: {4113 known: {
4081 const fn_decl = fn_decl: {4114 const fn_decl = fn_decl: {
4082 const callee_val = f.air.value(pl_op.operand) orelse break :known;4115 const callee_val = f.air.value(pl_op.operand) orelse break :known;
4083 break :fn_decl switch (callee_val.tag()) {4116 break :fn_decl switch (callee_val.tag()) {
4084 .extern_fn => blk: {4117 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
4085 is_extern = true;
4086 break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
4087 },
4088 .function => callee_val.castTag(.function).?.data.owner_decl,4118 .function => callee_val.castTag(.function).?.data.owner_decl,
4089 .decl_ref => callee_val.castTag(.decl_ref).?.data,4119 .decl_ref => callee_val.castTag(.decl_ref).?.data,
4090 else => break :known,4120 else => break :known,
4091 };4121 };
4092 };4122 };
4093 name = module.declPtr(fn_decl).name;4123 switch (modifier) {
4094 try f.object.dg.renderDeclName(writer, fn_decl, 0);4124 .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0),
4125 inline .never_tail, .never_inline => |mod| try writer.writeAll(try f.getLazyFnName(
4126 @unionInit(LazyFnKey, @tagName(mod), fn_decl),
4127 @unionInit(LazyFnValue.Data, @tagName(mod), {}),
4128 )),
4129 else => unreachable,
4130 }
4095 break :callee;4131 break :callee;
4096 }4132 }
4133 switch (modifier) {
4134 .auto, .always_tail => {},
4135 .never_tail => return f.fail("CBE: runtime callee with never_tail attribute unsupported", .{}),
4136 .never_inline => return f.fail("CBE: runtime callee with never_inline attribute unsupported", .{}),
4137 else => unreachable,
4138 }
4097 // Fall back to function pointer call.4139 // Fall back to function pointer call.
4098 try f.writeCValue(writer, callee, .Other);4140 try f.writeCValue(writer, callee, .Other);
4099 }4141 }
...@@ -4704,14 +4746,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4704,14 +4746,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4704 try writer.writeAll("register ");4746 try writer.writeAll("register ");
4705 const alignment = 0;4747 const alignment = 0;
4706 const local_value = try f.allocLocalValue(output_ty, alignment);4748 const local_value = try f.allocLocalValue(output_ty, alignment);
4707 try f.object.dg.renderTypeAndName(4749 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
4708 writer,
4709 output_ty,
4710 local_value,
4711 .mut,
4712 alignment,
4713 .Complete,
4714 );
4715 try writer.writeAll(" __asm(\"");4750 try writer.writeAll(" __asm(\"");
4716 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);4751 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4717 try writer.writeAll("\")");4752 try writer.writeAll("\")");
...@@ -4743,14 +4778,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4743,14 +4778,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4743 if (is_reg) try writer.writeAll("register ");4778 if (is_reg) try writer.writeAll("register ");
4744 const alignment = 0;4779 const alignment = 0;
4745 const local_value = try f.allocLocalValue(input_ty, alignment);4780 const local_value = try f.allocLocalValue(input_ty, alignment);
4746 try f.object.dg.renderTypeAndName(4781 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
4747 writer,
4748 input_ty,
4749 local_value,
4750 .@"const",
4751 alignment,
4752 .Complete,
4753 );
4754 if (is_reg) {4782 if (is_reg) {
4755 try writer.writeAll(" __asm(\"");4783 try writer.writeAll(" __asm(\"");
4756 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);4784 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
...@@ -6278,7 +6306,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6278,7 +6306,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6278 const writer = f.object.writer();6306 const writer = f.object.writer();
6279 const local = try f.allocLocal(inst, inst_ty);6307 const local = try f.allocLocal(inst, inst_ty);
6280 try f.writeCValue(writer, local, .Other);6308 try f.writeCValue(writer, local, .Other);
6281 try writer.print(" = {s}(", .{try f.getTagNameFn(enum_ty)});6309 try writer.print(" = {s}(", .{
6310 try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl() }, .{ .tag_name = enum_ty }),
6311 });
6282 try f.writeCValue(writer, operand, .Other);6312 try f.writeCValue(writer, operand, .Other);
6283 try writer.writeAll(");\n");6313 try writer.writeAll(");\n");
62846314
src/link/C.zig+14-21
...@@ -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, lazy fwd, lazy code.250 // Covers defines, zig.h, ctypes, asm, lazy fwd.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 6);251 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
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);
...@@ -263,8 +263,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -263,8 +263,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
263 f.appendBufAssumeCapacity(asm_buf.items);263 f.appendBufAssumeCapacity(asm_buf.items);
264 }264 }
265265
266 const lazy_indices = f.all_buffers.items.len;266 const lazy_index = f.all_buffers.items.len;
267 f.all_buffers.items.len += 2;267 f.all_buffers.items.len += 1;
268268
269 try self.flushErrDecls(&f.lazy_db);269 try self.flushErrDecls(&f.lazy_db);
270270
...@@ -297,6 +297,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -297,6 +297,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
297297
298 {298 {
299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
300 // This ensures that every lazy CType.Index exactly matches the global CType.Index.
300 assert(f.ctypes.count() == 0);301 assert(f.ctypes.count() == 0);
301 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);302 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);
302303
...@@ -305,30 +306,22 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -305,30 +306,22 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
305 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);306 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
306 }307 }
307308
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
322 f.all_buffers.items[ctypes_index] = .{309 f.all_buffers.items[ctypes_index] = .{
323 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",310 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
324 .iov_len = f.ctypes_buf.items.len,311 .iov_len = f.ctypes_buf.items.len,
325 };312 };
326 f.file_size += f.ctypes_buf.items.len;313 f.file_size += f.ctypes_buf.items.len;
327314
315 f.all_buffers.items[lazy_index] = .{
316 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
317 .iov_len = f.lazy_db.fwd_decl.items.len,
318 };
319 f.file_size += f.lazy_db.fwd_decl.items.len;
320
328 // Now the code.321 // Now the code.
329 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);322 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);
330 for (decl_values) |decl|323 f.appendBufAssumeCapacity(f.lazy_db.code.items);
331 f.appendBufAssumeCapacity(decl.code.items);324 for (decl_values) |decl| f.appendBufAssumeCapacity(decl.code.items);
332325
333 const file = self.base.file.?;326 const file = self.base.file.?;
334 try file.setEndPos(f.file_size);327 try file.setEndPos(f.file_size);
src/target.zig+1
...@@ -723,6 +723,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {...@@ -723,6 +723,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {
723pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {723pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {
724 switch (backend) {724 switch (backend) {
725 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),725 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
726 .stage2_c => return true,
726 else => return false,727 else => return false,
727 }728 }
728}729}