authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-28 02:10:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-19 19:08:59+01:00
log51706af908e0c6acb822ef36760b7fe31faf62a6
treed814bcfcfd83ebc5fd50da11f18a9a6427a54859
parent8573836892ba1b7cd34d377b46258930161256c3
signaturelock-open Commit is signed but in an unrecognized format.

compiler: introduce new `CallingConvention`

This commit begins implementing accepted proposal #21209 by making `std.builtin.CallingConvention` a tagged union. The stage1 dance here is a little convoluted. This commit introduces the new type as `NewCallingConvention`, keeping the old `CallingConvention` around. The compiler uses `std.builtin.NewCallingConvention` exclusively, but when fetching the type from `std` when running the compiler (e.g. with `getBuiltinType`), the name `CallingConvention` is used. This allows a prior build of Zig to be used to build this commit. The next commit will update `zig1.wasm`, and then the compiler and standard library can be updated to completely replace `CallingConvention` with `NewCallingConvention`. The second half of #21209 is to remove `@setAlignStack`, which will be implemented in another commit after updating `zig1.wasm`.

28 files changed, 1762 insertions(+), 520 deletions(-)

lib/compiler/aro_translate_c/ast.zig+56-8
...@@ -550,12 +550,24 @@ pub const Payload = struct {...@@ -550,12 +550,24 @@ pub const Payload = struct {
550 is_var_args: bool,550 is_var_args: bool,
551 name: ?[]const u8,551 name: ?[]const u8,
552 linksection_string: ?[]const u8,552 linksection_string: ?[]const u8,
553 explicit_callconv: ?std.builtin.CallingConvention,553 explicit_callconv: ?CallingConvention,
554 params: []Param,554 params: []Param,
555 return_type: Node,555 return_type: Node,
556 body: ?Node,556 body: ?Node,
557 alignment: ?c_uint,557 alignment: ?c_uint,
558 },558 },
559
560 pub const CallingConvention = enum {
561 c,
562 x86_64_sysv,
563 x86_stdcall,
564 x86_fastcall,
565 x86_thiscall,
566 x86_vectorcall,
567 aarch64_vfabi,
568 arm_aapcs,
569 arm_aapcs_vfp,
570 };
559 };571 };
560572
561 pub const Param = struct {573 pub const Param = struct {
...@@ -2812,14 +2824,50 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {...@@ -2812,14 +2824,50 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
2812 const callconv_expr = if (payload.explicit_callconv) |some| blk: {2824 const callconv_expr = if (payload.explicit_callconv) |some| blk: {
2813 _ = try c.addToken(.keyword_callconv, "callconv");2825 _ = try c.addToken(.keyword_callconv, "callconv");
2814 _ = try c.addToken(.l_paren, "(");2826 _ = try c.addToken(.l_paren, "(");
2815 _ = try c.addToken(.period, ".");2827 const cc_node = switch (some) {
2816 const res = try c.addNode(.{2828 .c => cc_node: {
2817 .tag = .enum_literal,2829 _ = try c.addToken(.period, ".");
2818 .main_token = try c.addTokenFmt(.identifier, "{s}", .{@tagName(some)}),2830 break :cc_node try c.addNode(.{
2819 .data = undefined,2831 .tag = .enum_literal,
2820 });2832 .main_token = try c.addToken(.identifier, "c"),
2833 .data = undefined,
2834 });
2835 },
2836 .x86_64_sysv,
2837 .x86_stdcall,
2838 .x86_fastcall,
2839 .x86_thiscall,
2840 .x86_vectorcall,
2841 .aarch64_vfabi,
2842 .arm_aapcs,
2843 .arm_aapcs_vfp,
2844 => cc_node: {
2845 // .{ .foo = .{} }
2846 _ = try c.addToken(.period, ".");
2847 const outer_lbrace = try c.addToken(.l_brace, "{");
2848 _ = try c.addToken(.period, ".");
2849 _ = try c.addToken(.identifier, @tagName(some));
2850 _ = try c.addToken(.equal, "=");
2851 _ = try c.addToken(.period, ".");
2852 const inner_lbrace = try c.addToken(.l_brace, "{");
2853 _ = try c.addToken(.r_brace, "}");
2854 _ = try c.addToken(.r_brace, "}");
2855 break :cc_node try c.addNode(.{
2856 .tag = .struct_init_dot_two,
2857 .main_token = outer_lbrace,
2858 .data = .{
2859 .lhs = try c.addNode(.{
2860 .tag = .struct_init_dot_two,
2861 .main_token = inner_lbrace,
2862 .data = .{ .lhs = 0, .rhs = 0 },
2863 }),
2864 .rhs = 0,
2865 },
2866 });
2867 },
2868 };
2821 _ = try c.addToken(.r_paren, ")");2869 _ = try c.addToken(.r_paren, ")");
2822 break :blk res;2870 break :blk cc_node;
2823 } else 0;2871 } else 0;
28242872
2825 const return_type_expr = try renderNode(c, payload.return_type);2873 const return_type_expr = try renderNode(c, payload.return_type);
lib/std/Target.zig+223
...@@ -1609,6 +1609,165 @@ pub const Cpu = struct {...@@ -1609,6 +1609,165 @@ pub const Cpu = struct {
1609 else => ".X",1609 else => ".X",
1610 };1610 };
1611 }1611 }
1612
1613 /// Returns the array of `Arch` to which a specific `std.builtin.CallingConvention` applies.
1614 /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`.
1615 pub fn fromCallconv(cc: std.builtin.NewCallingConvention) []const Arch {
1616 return switch (cc) {
1617 .auto,
1618 .@"async",
1619 .naked,
1620 .@"inline",
1621 => unreachable,
1622
1623 .x86_64_sysv,
1624 .x86_64_win,
1625 .x86_64_regcall_v3_sysv,
1626 .x86_64_regcall_v4_win,
1627 .x86_64_vectorcall,
1628 .x86_64_interrupt,
1629 => &.{.x86_64},
1630
1631 .x86_sysv,
1632 .x86_win,
1633 .x86_stdcall,
1634 .x86_fastcall,
1635 .x86_thiscall,
1636 .x86_thiscall_mingw,
1637 .x86_regcall_v3,
1638 .x86_regcall_v4_win,
1639 .x86_vectorcall,
1640 .x86_interrupt,
1641 => &.{.x86},
1642
1643 .aarch64_aapcs,
1644 .aarch64_aapcs_darwin,
1645 .aarch64_aapcs_win,
1646 .aarch64_vfabi,
1647 .aarch64_vfabi_sve,
1648 => &.{ .aarch64, .aarch64_be },
1649
1650 .arm_apcs,
1651 .arm_aapcs,
1652 .arm_aapcs_vfp,
1653 .arm_aapcs16_vfp,
1654 .arm_interrupt,
1655 => &.{ .arm, .armeb, .thumb, .thumbeb },
1656
1657 .mips64_n64,
1658 .mips64_n32,
1659 .mips64_interrupt,
1660 => &.{ .mips64, .mips64el },
1661
1662 .mips_o32,
1663 .mips_interrupt,
1664 => &.{ .mips, .mipsel },
1665
1666 .riscv64_lp64,
1667 .riscv64_lp64_v,
1668 .riscv64_interrupt,
1669 => &.{.riscv64},
1670
1671 .riscv32_ilp32,
1672 .riscv32_ilp32_v,
1673 .riscv32_interrupt,
1674 => &.{.riscv32},
1675
1676 .sparc64_sysv,
1677 => &.{.sparc64},
1678
1679 .sparc_sysv,
1680 => &.{.sparc},
1681
1682 .powerpc64_elf,
1683 .powerpc64_elf_altivec,
1684 .powerpc64_elf_v2,
1685 => &.{ .powerpc64, .powerpc64le },
1686
1687 .powerpc_sysv,
1688 .powerpc_sysv_altivec,
1689 .powerpc_aix,
1690 .powerpc_aix_altivec,
1691 => &.{ .powerpc, .powerpcle },
1692
1693 .wasm_watc,
1694 => &.{ .wasm64, .wasm32 },
1695
1696 .arc_sysv,
1697 => &.{.arc},
1698
1699 .avr_gnu,
1700 .avr_builtin,
1701 .avr_signal,
1702 .avr_interrupt,
1703 => &.{.avr},
1704
1705 .bpf_std,
1706 => &.{ .bpfel, .bpfeb },
1707
1708 .csky_sysv,
1709 .csky_interrupt,
1710 => &.{.csky},
1711
1712 .hexagon_sysv,
1713 .hexagon_sysv_hvx,
1714 => &.{.hexagon},
1715
1716 .lanai_sysv,
1717 => &.{.lanai},
1718
1719 .loongarch64_lp64,
1720 => &.{.loongarch64},
1721
1722 .loongarch32_ilp32,
1723 => &.{.loongarch32},
1724
1725 .m68k_sysv,
1726 .m68k_gnu,
1727 .m68k_rtd,
1728 .m68k_interrupt,
1729 => &.{.m68k},
1730
1731 .msp430_eabi,
1732 => &.{.msp430},
1733
1734 .propeller1_sysv,
1735 => &.{.propeller1},
1736
1737 .propeller2_sysv,
1738 => &.{.propeller2},
1739
1740 .s390x_sysv,
1741 .s390x_sysv_vx,
1742 => &.{.s390x},
1743
1744 .ve_sysv,
1745 => &.{.ve},
1746
1747 .xcore_xs1,
1748 .xcore_xs2,
1749 => &.{.xcore},
1750
1751 .xtensa_call0,
1752 .xtensa_windowed,
1753 => &.{.xtensa},
1754
1755 .amdgcn_device,
1756 .amdgcn_kernel,
1757 .amdgcn_cs,
1758 => &.{.amdgcn},
1759
1760 .nvptx_device,
1761 .nvptx_kernel,
1762 => &.{ .nvptx, .nvptx64 },
1763
1764 .spirv_device,
1765 .spirv_kernel,
1766 .spirv_fragment,
1767 .spirv_vertex,
1768 => &.{ .spirv, .spirv32, .spirv64 },
1769 };
1770 }
1612 };1771 };
16131772
1614 pub const Model = struct {1773 pub const Model = struct {
...@@ -2873,6 +3032,70 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {...@@ -2873,6 +3032,70 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
2873 );3032 );
2874}3033}
28753034
3035pub fn defaultCCallingConvention(target: Target) ?std.builtin.NewCallingConvention {
3036 return switch (target.cpu.arch) {
3037 .x86_64 => switch (target.os.tag) {
3038 .windows, .uefi => .{ .x86_64_win = .{} },
3039 else => .{ .x86_64_sysv = .{} },
3040 },
3041 .x86 => switch (target.os.tag) {
3042 .windows, .uefi => .{ .x86_win = .{} },
3043 else => .{ .x86_sysv = .{} },
3044 },
3045 .aarch64, .aarch64_be => if (target.os.tag.isDarwin()) cc: {
3046 break :cc .{ .aarch64_aapcs_darwin = .{} };
3047 } else switch (target.os.tag) {
3048 .windows => .{ .aarch64_aapcs_win = .{} },
3049 else => .{ .aarch64_aapcs = .{} },
3050 },
3051 .arm, .armeb, .thumb, .thumbeb => .{ .arm_aapcs = .{} },
3052 .mips64, .mips64el => switch (target.abi) {
3053 .gnuabin32 => .{ .mips64_n32 = .{} },
3054 else => .{ .mips64_n64 = .{} },
3055 },
3056 .mips, .mipsel => .{ .mips_o32 = .{} },
3057 .riscv64 => .{ .riscv64_lp64 = .{} },
3058 .riscv32 => .{ .riscv32_ilp32 = .{} },
3059 .sparc64 => .{ .sparc64_sysv = .{} },
3060 .sparc => .{ .sparc_sysv = .{} },
3061 .powerpc64 => if (target.isMusl())
3062 .{ .powerpc64_elf_v2 = .{} }
3063 else
3064 .{ .powerpc64_elf = .{} },
3065 .powerpc64le => .{ .powerpc64_elf_v2 = .{} },
3066 .powerpc, .powerpcle => switch (target.os.tag) {
3067 .aix => .{ .powerpc_aix = .{} },
3068 else => .{ .powerpc_sysv = .{} },
3069 },
3070 .wasm32 => .{ .wasm_watc = .{} },
3071 .wasm64 => .{ .wasm_watc = .{} },
3072 .arc => .{ .arc_sysv = .{} },
3073 .avr => .avr_gnu,
3074 .bpfel, .bpfeb => .{ .bpf_std = .{} },
3075 .csky => .{ .csky_sysv = .{} },
3076 .hexagon => .{ .hexagon_sysv = .{} },
3077 .kalimba => null,
3078 .lanai => .{ .lanai_sysv = .{} },
3079 .loongarch64 => .{ .loongarch64_lp64 = .{} },
3080 .loongarch32 => .{ .loongarch32_ilp32 = .{} },
3081 .m68k => if (target.abi.isGnu() or target.abi.isMusl())
3082 .{ .m68k_gnu = .{} }
3083 else
3084 .{ .m68k_sysv = .{} },
3085 .msp430 => .{ .msp430_eabi = .{} },
3086 .propeller1 => .{ .propeller1_sysv = .{} },
3087 .propeller2 => .{ .propeller2_sysv = .{} },
3088 .s390x => .{ .s390x_sysv = .{} },
3089 .spu_2 => null,
3090 .ve => .{ .ve_sysv = .{} },
3091 .xcore => .{ .xcore_xs1 = .{} },
3092 .xtensa => .{ .xtensa_call0 = .{} },
3093 .amdgcn => .{ .amdgcn_device = .{} },
3094 .nvptx, .nvptx64 => .nvptx_device,
3095 .spirv, .spirv32, .spirv64 => .spirv_device,
3096 };
3097}
3098
2876pub fn osArchName(target: std.Target) [:0]const u8 {3099pub fn osArchName(target: std.Target) [:0]const u8 {
2877 return target.os.tag.archName(target.cpu.arch);3100 return target.os.tag.archName(target.cpu.arch);
2878}3101}
lib/std/builtin.zig+330
...@@ -210,6 +210,336 @@ pub const CallingConvention = enum(u8) {...@@ -210,6 +210,336 @@ pub const CallingConvention = enum(u8) {
210 Vertex,210 Vertex,
211};211};
212212
213/// The calling convention of a function defines how arguments and return values are passed, as well
214/// as any other requirements which callers and callees must respect, such as register preservation
215/// and stack alignment.
216///
217/// This data structure is used by the Zig language code generation and
218/// therefore must be kept in sync with the compiler implementation.
219///
220/// TODO: this will be renamed `CallingConvention` after an initial zig1.wasm update.
221pub const NewCallingConvention = union(enum(u8)) {
222 pub const Tag = @typeInfo(NewCallingConvention).@"union".tag_type.?;
223
224 /// This is an alias for the default C calling convention for this target.
225 /// Functions marked as `extern` or `export` are given this calling convention by default.
226 pub const c = builtin.target.defaultCCallingConvention().?;
227
228 pub const winapi: NewCallingConvention = switch (builtin.target.arch) {
229 .x86_64 => .{ .x86_64_win = .{} },
230 .x86 => .{ .x86_stdcall = .{} },
231 .aarch64, .aarch64_be => .{ .aarch64_aapcs_win = .{} },
232 .arm, .armeb, .thumb, .thumbeb => .{ .arm_aapcs_vfp = .{} },
233 else => unreachable,
234 };
235
236 pub const kernel: NewCallingConvention = switch (builtin.target.cpu.arch) {
237 .amdgcn => .amdgcn_kernel,
238 .nvptx, .nvptx64 => .nvptx_kernel,
239 .spirv, .spirv32, .spirv64 => .spirv_kernel,
240 else => unreachable,
241 };
242
243 /// Deprecated; use `.auto`.
244 pub const Unspecified: NewCallingConvention = .auto;
245 /// Deprecated; use `.c`.
246 pub const C: NewCallingConvention = .c;
247 /// Deprecated; use `.naked`.
248 pub const Naked: NewCallingConvention = .naked;
249 /// Deprecated; use `.@"async"`.
250 pub const Async: NewCallingConvention = .@"async";
251 /// Deprecated; use `.@"inline"`.
252 pub const Inline: NewCallingConvention = .@"inline";
253 /// Deprecated; use `.x86_64_interrupt`, `.x86_interrupt`, or `.avr_interrupt`.
254 pub const Interrupt: NewCallingConvention = switch (builtin.target.cpu.arch) {
255 .x86_64 => .{ .x86_64_interrupt = .{} },
256 .x86 => .{ .x86_interrupt = .{} },
257 .avr => .avr_interrupt,
258 else => unreachable,
259 };
260 /// Deprecated; use `.avr_signal`.
261 pub const Signal: NewCallingConvention = .avr_signal;
262 /// Deprecated; use `.x86_stdcall`.
263 pub const Stdcall: NewCallingConvention = .{ .x86_stdcall = .{} };
264 /// Deprecated; use `.x86_fastcall`.
265 pub const Fastcall: NewCallingConvention = .{ .x86_fastcall = .{} };
266 /// Deprecated; use `.x86_64_vectorcall`, `.x86_vectorcall`, or `aarch64_vfabi`.
267 pub const Vectorcall: NewCallingConvention = switch (builtin.target.cpu.arch) {
268 .x86_64 => .{ .x86_64_vectorcall = .{} },
269 .x86 => .{ .x86_vectorcall = .{} },
270 .aarch64, .aarch64_be => .{ .aarch64_vfabi = .{} },
271 else => unreachable,
272 };
273 /// Deprecated; use `.x86_thiscall`.
274 pub const Thiscall: NewCallingConvention = .{ .x86_thiscall = .{} };
275 /// Deprecated; use `.arm_apcs`.
276 pub const APCS: NewCallingConvention = .{ .arm_apcs = .{} };
277 /// Deprecated; use `.arm_aapcs`.
278 pub const AAPCS: NewCallingConvention = .{ .arm_aapcs = .{} };
279 /// Deprecated; use `.arm_aapcs_vfp`.
280 pub const AAPCSVFP: NewCallingConvention = .{ .arm_aapcs_vfp = .{} };
281 /// Deprecated; use `.x86_64_sysv`.
282 pub const SysV: NewCallingConvention = .{ .x86_64_sysv = .{} };
283 /// Deprecated; use `.x86_64_win`.
284 pub const Win64: NewCallingConvention = .{ .x86_64_win = .{} };
285 /// Deprecated; use `.kernel`.
286 pub const Kernel: NewCallingConvention = .kernel;
287 /// Deprecated; use `.spirv_fragment`.
288 pub const Fragment: NewCallingConvention = .spirv_fragment;
289 /// Deprecated; use `.spirv_vertex`.
290 pub const Vertex: NewCallingConvention = .spirv_vertex;
291
292 /// The default Zig calling convention when neither `export` nor `inline` is specified.
293 /// This calling convention makes no guarantees about stack alignment, registers, etc.
294 /// It can only be used within this Zig compilation unit.
295 auto,
296
297 /// The calling convention of a function that can be called with `async` syntax. An `async` call
298 /// of a runtime-known function must target a function with this calling convention.
299 /// Comptime-known functions with other calling conventions may be coerced to this one.
300 @"async",
301
302 /// Functions with this calling convention have no prologue or epilogue, making the function
303 /// uncallable in regular Zig code. This can be useful when integrating with assembly.
304 naked,
305
306 /// This calling convention is exactly equivalent to using the `inline` keyword on a function
307 /// definition. This function will be semantically inlined by the Zig compiler at call sites.
308 /// Pointers to inline functions are comptime-only.
309 @"inline",
310
311 // Calling conventions for the x86_64 architecture.
312 x86_64_sysv: CommonOptions,
313 x86_64_win: CommonOptions,
314 x86_64_regcall_v3_sysv: CommonOptions,
315 x86_64_regcall_v4_win: CommonOptions,
316 x86_64_vectorcall: CommonOptions,
317 x86_64_interrupt: CommonOptions,
318
319 // Calling conventions for the x86 architecture.
320 x86_sysv: X86RegparmOptions,
321 x86_win: X86RegparmOptions,
322 x86_stdcall: X86RegparmOptions,
323 x86_fastcall: CommonOptions,
324 x86_thiscall: CommonOptions,
325 x86_thiscall_mingw: CommonOptions,
326 x86_regcall_v3: CommonOptions,
327 x86_regcall_v4_win: CommonOptions,
328 x86_vectorcall: CommonOptions,
329 x86_interrupt: CommonOptions,
330
331 // Calling conventions for the aarch64 architecture.
332 aarch64_aapcs: CommonOptions,
333 aarch64_aapcs_darwin: CommonOptions,
334 aarch64_aapcs_win: CommonOptions,
335 aarch64_vfabi: CommonOptions,
336 aarch64_vfabi_sve: CommonOptions,
337
338 // Calling convetions for the arm architecture.
339 /// ARM Procedure Call Standard (obsolete)
340 arm_apcs: CommonOptions,
341 /// ARM Architecture Procedure Call Standard
342 arm_aapcs: CommonOptions,
343 /// ARM Architecture Procedure Call Standard Vector Floating-Point
344 arm_aapcs_vfp: CommonOptions,
345 arm_aapcs16_vfp: CommonOptions,
346 arm_interrupt: ArmInterruptOptions,
347
348 // Calling conventions for the mips64 architecture.
349 mips64_n64: CommonOptions,
350 mips64_n32: CommonOptions,
351 mips64_interrupt: MipsInterruptOptions,
352
353 // Calling conventions for the mips architecture.
354 mips_o32: CommonOptions,
355 mips_interrupt: MipsInterruptOptions,
356
357 // Calling conventions for the riscv64 architecture.
358 riscv64_lp64: CommonOptions,
359 riscv64_lp64_v: CommonOptions,
360 riscv64_interrupt: RiscvInterruptOptions,
361
362 // Calling conventions for the riscv32 architecture.
363 riscv32_ilp32: CommonOptions,
364 riscv32_ilp32_v: CommonOptions,
365 riscv32_interrupt: RiscvInterruptOptions,
366
367 // Calling conventions for the sparc64 architecture.
368 sparc64_sysv: CommonOptions,
369
370 // Calling conventions for the sparc architecture.
371 sparc_sysv: CommonOptions,
372
373 // Calling conventions for the powerpc64 architecture.
374 powerpc64_elf: CommonOptions,
375 powerpc64_elf_altivec: CommonOptions,
376 powerpc64_elf_v2: CommonOptions,
377
378 // Calling conventions for the powerpc architecture.
379 powerpc_sysv: CommonOptions,
380 powerpc_sysv_altivec: CommonOptions,
381 powerpc_aix: CommonOptions,
382 powerpc_aix_altivec: CommonOptions,
383
384 /// The standard wasm32/wasm64 calling convention, as specified in the WebAssembly Tool Conventions.
385 wasm_watc: CommonOptions,
386
387 /// The standard ARC calling convention.
388 arc_sysv: CommonOptions,
389
390 // Calling conventions for the AVR architecture.
391 avr_gnu,
392 avr_builtin,
393 avr_signal,
394 avr_interrupt,
395
396 /// The standard bpf calling convention.
397 bpf_std: CommonOptions,
398
399 // Calling conventions for the csky architecture.
400 csky_sysv: CommonOptions,
401 csky_interrupt: CommonOptions,
402
403 // Calling conventions for the hexagon architecture.
404 hexagon_sysv: CommonOptions,
405 hexagon_sysv_hvx: CommonOptions,
406
407 /// The standard Lanai calling convention.
408 lanai_sysv: CommonOptions,
409
410 /// The standard loongarch64 calling convention.
411 loongarch64_lp64: CommonOptions,
412
413 /// The standard loongarch32 calling convention.
414 loongarch32_ilp32: CommonOptions,
415
416 // Calling conventions for the m68k architecture.
417 m68k_sysv: CommonOptions,
418 m68k_gnu: CommonOptions,
419 m68k_rtd: CommonOptions,
420 m68k_interrupt: CommonOptions,
421
422 /// The standard MSP430 calling convention.
423 msp430_eabi: CommonOptions,
424
425 /// The standard propeller1 calling convention.
426 propeller1_sysv: CommonOptions,
427
428 /// The standard propeller1 calling convention.
429 propeller2_sysv: CommonOptions,
430
431 // Calling conventions for the S390X architecture.
432 s390x_sysv: CommonOptions,
433 s390x_sysv_vx: CommonOptions,
434
435 /// The standard VE calling convention.
436 ve_sysv: CommonOptions,
437
438 // Calling conventions for the xCORE architecture.
439 xcore_xs1: CommonOptions,
440 xcore_xs2: CommonOptions,
441
442 // Calling conventions for the Xtensa architecture.
443 xtensa_call0: CommonOptions,
444 xtensa_windowed: CommonOptions,
445
446 // Calling conventions for the AMDGCN architecture.
447 amdgcn_device: CommonOptions,
448 amdgcn_kernel,
449 amdgcn_cs: CommonOptions,
450
451 // Calling conventions for the NVPTX architecture.
452 nvptx_device,
453 nvptx_kernel,
454
455 // Calling conventions for SPIR-V kernels and shaders.
456 spirv_device,
457 spirv_kernel,
458 spirv_fragment,
459 spirv_vertex,
460
461 /// Options shared across most calling conventions.
462 pub const CommonOptions = struct {
463 /// The boundary the stack is aligned to when the function is called.
464 /// `null` means the default for this calling convention.
465 incoming_stack_alignment: ?u64 = null,
466 };
467
468 /// Options for x86 calling conventions which support the regparm attribute to pass some
469 /// arguments in registers.
470 pub const X86RegparmOptions = struct {
471 /// The boundary the stack is aligned to when the function is called.
472 /// `null` means the default for this calling convention.
473 incoming_stack_alignment: ?u64 = null,
474 /// The number of arguments to pass in registers before passing the remaining arguments
475 /// according to the calling convention.
476 /// Equivalent to `__attribute__((regparm(x)))` in Clang and GCC.
477 register_params: u2 = 0,
478 };
479
480 /// Options for the `arm_interrupt` calling convention.
481 pub const ArmInterruptOptions = struct {
482 /// The boundary the stack is aligned to when the function is called.
483 /// `null` means the default for this calling convention.
484 incoming_stack_alignment: ?u64 = null,
485 /// The kind of interrupt being received.
486 type: InterruptType = .generic,
487
488 pub const InterruptType = enum(u3) {
489 generic,
490 irq,
491 fiq,
492 swi,
493 abort,
494 undef,
495 };
496 };
497
498 /// Options for the `mips_interrupt` and `mips64_interrupt` calling conventions.
499 pub const MipsInterruptOptions = struct {
500 /// The boundary the stack is aligned to when the function is called.
501 /// `null` means the default for this calling convention.
502 incoming_stack_alignment: ?u64 = null,
503 /// The interrupt mode.
504 mode: InterruptMode = .eic,
505
506 pub const InterruptMode = enum(u4) {
507 eic,
508 sw0,
509 sw1,
510 hw0,
511 hw1,
512 hw2,
513 hw3,
514 hw4,
515 hw5,
516 };
517 };
518
519 /// Options for the `riscv32_interrupt` and `riscv64_interrupt` calling conventions.
520 pub const RiscvInterruptOptions = struct {
521 /// The boundary the stack is aligned to when the function is called.
522 /// `null` means the default for this calling convention.
523 incoming_stack_alignment: ?u64 = null,
524 /// The privilege level.
525 level: PrivilegeLevel = .machine,
526
527 pub const PrivilegeLevel = enum(u2) {
528 user,
529 supervisor,
530 machine,
531 };
532 };
533
534 /// Returns the array of `std.Target.Cpu.Arch` to which this `CallingConvention` applies.
535 /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`.
536 pub const archs = std.Target.Cpu.Arch.fromCallconv;
537
538 pub fn eql(a: NewCallingConvention, b: NewCallingConvention) bool {
539 return std.meta.eql(a, b);
540 }
541};
542
213/// This data structure is used by the Zig language code generation and543/// This data structure is used by the Zig language code generation and
214/// therefore must be kept in sync with the compiler implementation.544/// therefore must be kept in sync with the compiler implementation.
215pub const AddressSpace = enum(u5) {545pub const AddressSpace = enum(u5) {
src/InternPool.zig+92-13
...@@ -1988,7 +1988,7 @@ pub const Key = union(enum) {...@@ -1988,7 +1988,7 @@ pub const Key = union(enum) {
1988 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper1988 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper
1989 /// method for accessing this.1989 /// method for accessing this.
1990 noalias_bits: u32,1990 noalias_bits: u32,
1991 cc: std.builtin.CallingConvention,1991 cc: std.builtin.NewCallingConvention,
1992 is_var_args: bool,1992 is_var_args: bool,
1993 is_generic: bool,1993 is_generic: bool,
1994 is_noinline: bool,1994 is_noinline: bool,
...@@ -2011,10 +2011,10 @@ pub const Key = union(enum) {...@@ -2011,10 +2011,10 @@ pub const Key = union(enum) {
2011 a.return_type == b.return_type and2011 a.return_type == b.return_type and
2012 a.comptime_bits == b.comptime_bits and2012 a.comptime_bits == b.comptime_bits and
2013 a.noalias_bits == b.noalias_bits and2013 a.noalias_bits == b.noalias_bits and
2014 a.cc == b.cc and
2015 a.is_var_args == b.is_var_args and2014 a.is_var_args == b.is_var_args and
2016 a.is_generic == b.is_generic and2015 a.is_generic == b.is_generic and
2017 a.is_noinline == b.is_noinline;2016 a.is_noinline == b.is_noinline and
2017 std.meta.eql(a.cc, b.cc);
2018 }2018 }
20192019
2020 pub fn hash(self: FuncType, hasher: *Hash, ip: *const InternPool) void {2020 pub fn hash(self: FuncType, hasher: *Hash, ip: *const InternPool) void {
...@@ -5444,7 +5444,7 @@ pub const Tag = enum(u8) {...@@ -5444,7 +5444,7 @@ pub const Tag = enum(u8) {
5444 flags: Flags,5444 flags: Flags,
54455445
5446 pub const Flags = packed struct(u32) {5446 pub const Flags = packed struct(u32) {
5447 cc: std.builtin.CallingConvention,5447 cc: PackedCallingConvention,
5448 is_var_args: bool,5448 is_var_args: bool,
5449 is_generic: bool,5449 is_generic: bool,
5450 has_comptime_bits: bool,5450 has_comptime_bits: bool,
...@@ -5453,7 +5453,7 @@ pub const Tag = enum(u8) {...@@ -5453,7 +5453,7 @@ pub const Tag = enum(u8) {
5453 cc_is_generic: bool,5453 cc_is_generic: bool,
5454 section_is_generic: bool,5454 section_is_generic: bool,
5455 addrspace_is_generic: bool,5455 addrspace_is_generic: bool,
5456 _: u16 = 0,5456 _: u6 = 0,
5457 };5457 };
5458 };5458 };
54595459
...@@ -6912,7 +6912,7 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke...@@ -6912,7 +6912,7 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke
6912 .return_type = type_function.data.return_type,6912 .return_type = type_function.data.return_type,
6913 .comptime_bits = comptime_bits,6913 .comptime_bits = comptime_bits,
6914 .noalias_bits = noalias_bits,6914 .noalias_bits = noalias_bits,
6915 .cc = type_function.data.flags.cc,6915 .cc = type_function.data.flags.cc.unpack(),
6916 .is_var_args = type_function.data.flags.is_var_args,6916 .is_var_args = type_function.data.flags.is_var_args,
6917 .is_noinline = type_function.data.flags.is_noinline,6917 .is_noinline = type_function.data.flags.is_noinline,
6918 .cc_is_generic = type_function.data.flags.cc_is_generic,6918 .cc_is_generic = type_function.data.flags.cc_is_generic,
...@@ -8526,7 +8526,7 @@ pub const GetFuncTypeKey = struct {...@@ -8526,7 +8526,7 @@ pub const GetFuncTypeKey = struct {
8526 comptime_bits: u32 = 0,8526 comptime_bits: u32 = 0,
8527 noalias_bits: u32 = 0,8527 noalias_bits: u32 = 0,
8528 /// `null` means generic.8528 /// `null` means generic.
8529 cc: ?std.builtin.CallingConvention = .Unspecified,8529 cc: ?std.builtin.NewCallingConvention = .auto,
8530 is_var_args: bool = false,8530 is_var_args: bool = false,
8531 is_generic: bool = false,8531 is_generic: bool = false,
8532 is_noinline: bool = false,8532 is_noinline: bool = false,
...@@ -8564,7 +8564,7 @@ pub fn getFuncType(...@@ -8564,7 +8564,7 @@ pub fn getFuncType(
8564 .params_len = params_len,8564 .params_len = params_len,
8565 .return_type = key.return_type,8565 .return_type = key.return_type,
8566 .flags = .{8566 .flags = .{
8567 .cc = key.cc orelse .Unspecified,8567 .cc = .pack(key.cc orelse .auto),
8568 .is_var_args = key.is_var_args,8568 .is_var_args = key.is_var_args,
8569 .has_comptime_bits = key.comptime_bits != 0,8569 .has_comptime_bits = key.comptime_bits != 0,
8570 .has_noalias_bits = key.noalias_bits != 0,8570 .has_noalias_bits = key.noalias_bits != 0,
...@@ -8668,7 +8668,7 @@ pub const GetFuncDeclKey = struct {...@@ -8668,7 +8668,7 @@ pub const GetFuncDeclKey = struct {
8668 rbrace_line: u32,8668 rbrace_line: u32,
8669 lbrace_column: u32,8669 lbrace_column: u32,
8670 rbrace_column: u32,8670 rbrace_column: u32,
8671 cc: ?std.builtin.CallingConvention,8671 cc: ?std.builtin.NewCallingConvention,
8672 is_noinline: bool,8672 is_noinline: bool,
8673};8673};
86748674
...@@ -8733,7 +8733,7 @@ pub const GetFuncDeclIesKey = struct {...@@ -8733,7 +8733,7 @@ pub const GetFuncDeclIesKey = struct {
8733 comptime_bits: u32,8733 comptime_bits: u32,
8734 bare_return_type: Index,8734 bare_return_type: Index,
8735 /// null means generic.8735 /// null means generic.
8736 cc: ?std.builtin.CallingConvention,8736 cc: ?std.builtin.NewCallingConvention,
8737 /// null means generic.8737 /// null means generic.
8738 alignment: ?Alignment,8738 alignment: ?Alignment,
8739 section_is_generic: bool,8739 section_is_generic: bool,
...@@ -8818,7 +8818,7 @@ pub fn getFuncDeclIes(...@@ -8818,7 +8818,7 @@ pub fn getFuncDeclIes(
8818 .params_len = params_len,8818 .params_len = params_len,
8819 .return_type = error_union_type,8819 .return_type = error_union_type,
8820 .flags = .{8820 .flags = .{
8821 .cc = key.cc orelse .Unspecified,8821 .cc = .pack(key.cc orelse .auto),
8822 .is_var_args = key.is_var_args,8822 .is_var_args = key.is_var_args,
8823 .has_comptime_bits = key.comptime_bits != 0,8823 .has_comptime_bits = key.comptime_bits != 0,
8824 .has_noalias_bits = key.noalias_bits != 0,8824 .has_noalias_bits = key.noalias_bits != 0,
...@@ -8948,7 +8948,7 @@ pub const GetFuncInstanceKey = struct {...@@ -8948,7 +8948,7 @@ pub const GetFuncInstanceKey = struct {
8948 comptime_args: []const Index,8948 comptime_args: []const Index,
8949 noalias_bits: u32,8949 noalias_bits: u32,
8950 bare_return_type: Index,8950 bare_return_type: Index,
8951 cc: std.builtin.CallingConvention,8951 cc: std.builtin.NewCallingConvention,
8952 alignment: Alignment,8952 alignment: Alignment,
8953 section: OptionalNullTerminatedString,8953 section: OptionalNullTerminatedString,
8954 is_noinline: bool,8954 is_noinline: bool,
...@@ -9110,7 +9110,7 @@ pub fn getFuncInstanceIes(...@@ -9110,7 +9110,7 @@ pub fn getFuncInstanceIes(
9110 .params_len = params_len,9110 .params_len = params_len,
9111 .return_type = error_union_type,9111 .return_type = error_union_type,
9112 .flags = .{9112 .flags = .{
9113 .cc = arg.cc,9113 .cc = .pack(arg.cc),
9114 .is_var_args = false,9114 .is_var_args = false,
9115 .has_comptime_bits = false,9115 .has_comptime_bits = false,
9116 .has_noalias_bits = arg.noalias_bits != 0,9116 .has_noalias_bits = arg.noalias_bits != 0,
...@@ -12224,3 +12224,82 @@ pub fn getErrorValue(...@@ -12224,3 +12224,82 @@ pub fn getErrorValue(
12224pub fn getErrorValueIfExists(ip: *const InternPool, name: NullTerminatedString) ?Zcu.ErrorInt {12224pub fn getErrorValueIfExists(ip: *const InternPool, name: NullTerminatedString) ?Zcu.ErrorInt {
12225 return @intFromEnum(ip.global_error_set.getErrorValueIfExists(name) orelse return null);12225 return @intFromEnum(ip.global_error_set.getErrorValueIfExists(name) orelse return null);
12226}12226}
12227
12228const PackedCallingConvention = packed struct(u18) {
12229 tag: std.builtin.NewCallingConvention.Tag,
12230 /// May be ignored depending on `tag`.
12231 incoming_stack_alignment: Alignment,
12232 /// Interpretation depends on `tag`.
12233 extra: u4,
12234
12235 fn pack(cc: std.builtin.NewCallingConvention) PackedCallingConvention {
12236 return switch (cc) {
12237 inline else => |pl, tag| switch (@TypeOf(pl)) {
12238 void => .{
12239 .tag = tag,
12240 .incoming_stack_alignment = .none, // unused
12241 .extra = 0, // unused
12242 },
12243 std.builtin.NewCallingConvention.CommonOptions => .{
12244 .tag = tag,
12245 .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0),
12246 .extra = 0, // unused
12247 },
12248 std.builtin.NewCallingConvention.X86RegparmOptions => .{
12249 .tag = tag,
12250 .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0),
12251 .extra = pl.register_params,
12252 },
12253 std.builtin.NewCallingConvention.ArmInterruptOptions => .{
12254 .tag = tag,
12255 .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0),
12256 .extra = @intFromEnum(pl.type),
12257 },
12258 std.builtin.NewCallingConvention.MipsInterruptOptions => .{
12259 .tag = tag,
12260 .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0),
12261 .extra = @intFromEnum(pl.mode),
12262 },
12263 std.builtin.NewCallingConvention.RiscvInterruptOptions => .{
12264 .tag = tag,
12265 .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0),
12266 .extra = @intFromEnum(pl.level),
12267 },
12268 else => comptime unreachable,
12269 },
12270 };
12271 }
12272
12273 fn unpack(cc: PackedCallingConvention) std.builtin.NewCallingConvention {
12274 @setEvalBranchQuota(400_000);
12275 return switch (cc.tag) {
12276 inline else => |tag| @unionInit(
12277 std.builtin.NewCallingConvention,
12278 @tagName(tag),
12279 switch (std.meta.FieldType(std.builtin.NewCallingConvention, tag)) {
12280 void => {},
12281 std.builtin.NewCallingConvention.CommonOptions => .{
12282 .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(),
12283 },
12284 std.builtin.NewCallingConvention.X86RegparmOptions => .{
12285 .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(),
12286 .register_params = @intCast(cc.extra),
12287 },
12288 std.builtin.NewCallingConvention.ArmInterruptOptions => .{
12289 .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(),
12290 .type = @enumFromInt(cc.extra),
12291 },
12292 std.builtin.NewCallingConvention.MipsInterruptOptions => .{
12293 .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(),
12294 .mode = @enumFromInt(cc.extra),
12295 },
12296 std.builtin.NewCallingConvention.RiscvInterruptOptions => .{
12297 .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(),
12298 .level = @enumFromInt(cc.extra),
12299 },
12300 else => comptime unreachable,
12301 },
12302 ),
12303 };
12304 }
12305};
src/Sema.zig+236-102
...@@ -26,7 +26,7 @@ owner: AnalUnit,...@@ -26,7 +26,7 @@ owner: AnalUnit,
26/// in the case of an inline or comptime function call.26/// in the case of an inline or comptime function call.
27/// This could be `none`, a `func_decl`, or a `func_instance`.27/// This could be `none`, a `func_decl`, or a `func_instance`.
28func_index: InternPool.Index,28func_index: InternPool.Index,
29/// Whether the type of func_index has a calling convention of `.Naked`.29/// Whether the type of func_index has a calling convention of `.naked`.
30func_is_naked: bool,30func_is_naked: bool,
31/// Used to restore the error return trace when returning a non-error from a function.31/// Used to restore the error return trace when returning a non-error from a function.
32error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,32error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
...@@ -1355,7 +1355,7 @@ fn analyzeBodyInner(...@@ -1355,7 +1355,7 @@ fn analyzeBodyInner(
1355 },1355 },
1356 .value_placeholder => unreachable, // never appears in a body1356 .value_placeholder => unreachable, // never appears in a body
1357 .field_parent_ptr => try sema.zirFieldParentPtr(block, extended),1357 .field_parent_ptr => try sema.zirFieldParentPtr(block, extended),
1358 .builtin_value => try sema.zirBuiltinValue(extended),1358 .builtin_value => try sema.zirBuiltinValue(block, extended),
1359 .inplace_arith_result_ty => try sema.zirInplaceArithResultTy(extended),1359 .inplace_arith_result_ty => try sema.zirInplaceArithResultTy(extended),
1360 };1360 };
1361 },1361 },
...@@ -2698,6 +2698,20 @@ fn analyzeAsInt(...@@ -2698,6 +2698,20 @@ fn analyzeAsInt(
2698 return try val.toUnsignedIntSema(sema.pt);2698 return try val.toUnsignedIntSema(sema.pt);
2699}2699}
27002700
2701fn analyzeValueAsCallconv(
2702 sema: *Sema,
2703 block: *Block,
2704 src: LazySrcLoc,
2705 unresolved_val: Value,
2706) !std.builtin.NewCallingConvention {
2707 const resolved_val = try sema.resolveLazyValue(unresolved_val);
2708 return resolved_val.interpret(std.builtin.NewCallingConvention, sema.pt) catch |err| switch (err) {
2709 error.OutOfMemory => |e| return e,
2710 error.UndefinedValue => return sema.failWithUseOfUndef(block, src),
2711 error.TypeMismatch => @panic("std.builtin is corrupt"),
2712 };
2713}
2714
2701/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,2715/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
2702/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.2716/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
2703fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {2717fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
...@@ -6516,8 +6530,8 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst...@@ -6516,8 +6530,8 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
6516 }6530 }
65176531
6518 switch (Value.fromInterned(func).typeOf(zcu).fnCallingConvention(zcu)) {6532 switch (Value.fromInterned(func).typeOf(zcu).fnCallingConvention(zcu)) {
6519 .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),6533 .naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
6520 .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}),6534 .@"inline" => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
6521 else => {},6535 else => {},
6522 }6536 }
65236537
...@@ -7554,7 +7568,7 @@ fn analyzeCall(...@@ -7554,7 +7568,7 @@ fn analyzeCall(
7554 if (try sema.resolveValue(func)) |func_val|7568 if (try sema.resolveValue(func)) |func_val|
7555 if (func_val.isUndef(zcu))7569 if (func_val.isUndef(zcu))
7556 return sema.failWithUseOfUndef(block, call_src);7570 return sema.failWithUseOfUndef(block, call_src);
7557 if (cc == .Naked) {7571 if (cc == .naked) {
7558 const maybe_func_inst = try sema.funcDeclSrcInst(func);7572 const maybe_func_inst = try sema.funcDeclSrcInst(func);
7559 const msg = msg: {7573 const msg = msg: {
7560 const msg = try sema.errMsg(7574 const msg = try sema.errMsg(
...@@ -7587,7 +7601,7 @@ fn analyzeCall(...@@ -7587,7 +7601,7 @@ fn analyzeCall(
7587 .async_kw => return sema.failWithUseOfAsync(block, call_src),7601 .async_kw => return sema.failWithUseOfAsync(block, call_src),
7588 };7602 };
75897603
7590 if (modifier == .never_inline and func_ty_info.cc == .Inline) {7604 if (modifier == .never_inline and func_ty_info.cc == .@"inline") {
7591 return sema.fail(block, call_src, "'never_inline' call of inline function", .{});7605 return sema.fail(block, call_src, "'never_inline' call of inline function", .{});
7592 }7606 }
7593 if (modifier == .always_inline and func_ty_info.is_noinline) {7607 if (modifier == .always_inline and func_ty_info.is_noinline) {
...@@ -7598,7 +7612,7 @@ fn analyzeCall(...@@ -7598,7 +7612,7 @@ fn analyzeCall(
75987612
7599 const is_generic_call = func_ty_info.is_generic;7613 const is_generic_call = func_ty_info.is_generic;
7600 var is_comptime_call = block.is_comptime or modifier == .compile_time;7614 var is_comptime_call = block.is_comptime or modifier == .compile_time;
7601 var is_inline_call = is_comptime_call or modifier == .always_inline or func_ty_info.cc == .Inline;7615 var is_inline_call = is_comptime_call or modifier == .always_inline or func_ty_info.cc == .@"inline";
7602 var comptime_reason: ?*const Block.ComptimeReason = null;7616 var comptime_reason: ?*const Block.ComptimeReason = null;
7603 if (!is_inline_call and !is_comptime_call) {7617 if (!is_inline_call and !is_comptime_call) {
7604 if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {7618 if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {
...@@ -8455,7 +8469,7 @@ fn instantiateGenericCall(...@@ -8455,7 +8469,7 @@ fn instantiateGenericCall(
8455 }8469 }
8456 // Similarly, if the call evaluated to a generic type we need to instead8470 // Similarly, if the call evaluated to a generic type we need to instead
8457 // call it inline.8471 // call it inline.
8458 if (func_ty_info.is_generic or func_ty_info.cc == .Inline) {8472 if (func_ty_info.is_generic or func_ty_info.cc == .@"inline") {
8459 return error.GenericPoison;8473 return error.GenericPoison;
8460 }8474 }
84618475
...@@ -9505,8 +9519,8 @@ fn zirFunc(...@@ -9505,8 +9519,8 @@ fn zirFunc(
95059519
9506 // If this instruction has a body, then it's a function declaration, and we decide9520 // If this instruction has a body, then it's a function declaration, and we decide
9507 // the callconv based on whether it is exported. Otherwise, the callconv defaults9521 // the callconv based on whether it is exported. Otherwise, the callconv defaults
9508 // to `.Unspecified`.9522 // to `.auto`.
9509 const cc: std.builtin.CallingConvention = if (has_body) cc: {9523 const cc: std.builtin.NewCallingConvention = if (has_body) cc: {
9510 const func_decl_cau = if (sema.generic_owner != .none) cau: {9524 const func_decl_cau = if (sema.generic_owner != .none) cau: {
9511 const generic_owner_fn = zcu.funcInfo(sema.generic_owner);9525 const generic_owner_fn = zcu.funcInfo(sema.generic_owner);
9512 // The generic owner definitely has a `Cau` for the corresponding function declaration.9526 // The generic owner definitely has a `Cau` for the corresponding function declaration.
...@@ -9518,8 +9532,26 @@ fn zirFunc(...@@ -9518,8 +9532,26 @@ fn zirFunc(
9518 const zir_decl = sema.code.getDeclaration(decl_inst)[0];9532 const zir_decl = sema.code.getDeclaration(decl_inst)[0];
9519 break :exported zir_decl.flags.is_export;9533 break :exported zir_decl.flags.is_export;
9520 };9534 };
9521 break :cc if (fn_is_exported) .C else .Unspecified;9535 if (fn_is_exported) {
9522 } else .Unspecified;9536 break :cc target.defaultCCallingConvention() orelse {
9537 // This target has no default C calling convention. We sometimes trigger a similar
9538 // error by trying to evaluate `std.builtin.CallingConvention.c`, so for consistency,
9539 // let's eval that now and just get the transitive error. (It's guaranteed to error
9540 // because it does the exact `defaultCCallingConvention` call we just did.)
9541 const cc_type = try sema.getBuiltinType("CallingConvention");
9542 _ = try sema.namespaceLookupVal(
9543 block,
9544 LazySrcLoc.unneeded,
9545 cc_type.getNamespaceIndex(zcu),
9546 try ip.getOrPutString(sema.gpa, pt.tid, "c", .no_embedded_nulls),
9547 );
9548 // The above should have errored.
9549 @panic("std.builtin is corrupt");
9550 };
9551 } else {
9552 break :cc .auto;
9553 }
9554 } else .auto;
95239555
9524 return sema.funcCommon(9556 return sema.funcCommon(
9525 block,9557 block,
...@@ -9654,15 +9686,64 @@ fn handleExternLibName(...@@ -9654,15 +9686,64 @@ fn handleExternLibName(
9654/// These are calling conventions that are confirmed to work with variadic functions.9686/// These are calling conventions that are confirmed to work with variadic functions.
9655/// Any calling conventions not included here are either not yet verified to work with variadic9687/// Any calling conventions not included here are either not yet verified to work with variadic
9656/// functions or there are no more other calling conventions that support variadic functions.9688/// functions or there are no more other calling conventions that support variadic functions.
9657const calling_conventions_supporting_var_args = [_]std.builtin.CallingConvention{9689const calling_conventions_supporting_var_args = [_]std.builtin.NewCallingConvention.Tag{
9658 .C,9690 .x86_64_sysv,
9691 .x86_64_win,
9692 .x86_sysv,
9693 .x86_win,
9694 .aarch64_aapcs,
9695 .aarch64_aapcs_darwin,
9696 .aarch64_aapcs_win,
9697 .aarch64_vfabi,
9698 .aarch64_vfabi_sve,
9699 .arm_apcs,
9700 .arm_aapcs,
9701 .arm_aapcs_vfp,
9702 .arm_aapcs16_vfp,
9703 .mips64_n64,
9704 .mips64_n32,
9705 .mips_o32,
9706 .riscv64_lp64,
9707 .riscv64_lp64_v,
9708 .riscv32_ilp32,
9709 .riscv32_ilp32_v,
9710 .sparc64_sysv,
9711 .sparc_sysv,
9712 .powerpc64_elf,
9713 .powerpc64_elf_altivec,
9714 .powerpc64_elf_v2,
9715 .powerpc_sysv,
9716 .powerpc_sysv_altivec,
9717 .powerpc_aix,
9718 .powerpc_aix_altivec,
9719 .wasm_watc,
9720 .arc_sysv,
9721 .avr_gnu,
9722 .bpf_std,
9723 .csky_sysv,
9724 .hexagon_sysv,
9725 .hexagon_sysv_hvx,
9726 .lanai_sysv,
9727 .loongarch64_lp64,
9728 .loongarch32_ilp32,
9729 .m68k_sysv,
9730 .m68k_gnu,
9731 .m68k_rtd,
9732 .msp430_eabi,
9733 .s390x_sysv,
9734 .s390x_sysv_vx,
9735 .ve_sysv,
9736 .xcore_xs1,
9737 .xcore_xs2,
9738 .xtensa_call0,
9739 .xtensa_windowed,
9659};9740};
9660fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention) bool {9741fn callConvSupportsVarArgs(cc: std.builtin.NewCallingConvention.Tag) bool {
9661 return for (calling_conventions_supporting_var_args) |supported_cc| {9742 return for (calling_conventions_supporting_var_args) |supported_cc| {
9662 if (cc == supported_cc) return true;9743 if (cc == supported_cc) return true;
9663 } else false;9744 } else false;
9664}9745}
9665fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention) CompileError!void {9746fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.NewCallingConvention.Tag) CompileError!void {
9666 const CallingConventionsSupportingVarArgsList = struct {9747 const CallingConventionsSupportingVarArgsList = struct {
9667 pub fn format(_: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {9748 pub fn format(_: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
9668 _ = fmt;9749 _ = fmt;
...@@ -9703,7 +9784,7 @@ fn funcCommon(...@@ -9703,7 +9784,7 @@ fn funcCommon(
9703 address_space: ?std.builtin.AddressSpace,9784 address_space: ?std.builtin.AddressSpace,
9704 section: Section,9785 section: Section,
9705 /// null means generic poison9786 /// null means generic poison
9706 cc: ?std.builtin.CallingConvention,9787 cc: ?std.builtin.NewCallingConvention,
9707 /// this might be Type.generic_poison9788 /// this might be Type.generic_poison
9708 bare_return_type: Type,9789 bare_return_type: Type,
9709 var_args: bool,9790 var_args: bool,
...@@ -9743,7 +9824,7 @@ fn funcCommon(...@@ -9743,7 +9824,7 @@ fn funcCommon(
9743 // default values which are only meaningful for the generic function, *not*9824 // default values which are only meaningful for the generic function, *not*
9744 // the instantiation, which can depend on comptime parameters.9825 // the instantiation, which can depend on comptime parameters.
9745 // Related proposal: https://github.com/ziglang/zig/issues/118349826 // Related proposal: https://github.com/ziglang/zig/issues/11834
9746 const cc_resolved = cc orelse .Unspecified;9827 const cc_resolved = cc orelse .auto;
9747 var comptime_bits: u32 = 0;9828 var comptime_bits: u32 = 0;
9748 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {9829 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {
9749 const param_ty = Type.fromInterned(param_ty_ip);9830 const param_ty = Type.fromInterned(param_ty_ip);
...@@ -9761,10 +9842,10 @@ fn funcCommon(...@@ -9761,10 +9842,10 @@ fn funcCommon(
9761 }9842 }
9762 const this_generic = param_ty.isGenericPoison();9843 const this_generic = param_ty.isGenericPoison();
9763 is_generic = is_generic or this_generic;9844 is_generic = is_generic or this_generic;
9764 if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved)) {9845 if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc_resolved)) {
9765 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});9846 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});
9766 }9847 }
9767 if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved)) {9848 if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(cc_resolved)) {
9768 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});9849 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});
9769 }9850 }
9770 if (!param_ty.isValidParamType(zcu)) {9851 if (!param_ty.isValidParamType(zcu)) {
...@@ -9773,7 +9854,7 @@ fn funcCommon(...@@ -9773,7 +9854,7 @@ fn funcCommon(
9773 opaque_str, param_ty.fmt(pt),9854 opaque_str, param_ty.fmt(pt),
9774 });9855 });
9775 }9856 }
9776 if (!this_generic and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and !try sema.validateExternType(param_ty, .param_ty)) {9857 if (!this_generic and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and !try sema.validateExternType(param_ty, .param_ty)) {
9777 const msg = msg: {9858 const msg = msg: {
9778 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{9859 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
9779 param_ty.fmt(pt), @tagName(cc_resolved),9860 param_ty.fmt(pt), @tagName(cc_resolved),
...@@ -9807,15 +9888,24 @@ fn funcCommon(...@@ -9807,15 +9888,24 @@ fn funcCommon(
9807 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});9888 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
9808 }9889 }
9809 switch (cc_resolved) {9890 switch (cc_resolved) {
9810 .Interrupt => if (target.cpu.arch.isX86()) {9891 .x86_64_interrupt, .x86_interrupt => {
9811 const err_code_size = target.ptrBitWidth();9892 const err_code_size = target.ptrBitWidth();
9812 switch (i) {9893 switch (i) {
9813 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with 'Interrupt' calling convention must be a pointer type", .{}),9894 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with 'Interrupt' calling convention must be a pointer type", .{}),
9814 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with 'Interrupt' calling convention must be a {d}-bit integer", .{err_code_size}),9895 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with 'Interrupt' calling convention must be a {d}-bit integer", .{err_code_size}),
9815 else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}),9896 else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}),
9816 }9897 }
9817 } else return sema.fail(block, param_src, "parameters are not allowed with 'Interrupt' calling convention", .{}),9898 },
9818 .Signal => return sema.fail(block, param_src, "parameters are not allowed with 'Signal' calling convention", .{}),9899 .arm_interrupt,
9900 .mips64_interrupt,
9901 .mips_interrupt,
9902 .riscv64_interrupt,
9903 .riscv32_interrupt,
9904 .avr_interrupt,
9905 .csky_interrupt,
9906 .m68k_interrupt,
9907 => return sema.fail(block, param_src, "parameters are not allowed with 'Interrupt' calling convention", .{}),
9908 .avr_signal => return sema.fail(block, param_src, "parameters are not allowed with 'Signal' calling convention", .{}),
9819 else => {},9909 else => {},
9820 }9910 }
9821 }9911 }
...@@ -10051,7 +10141,7 @@ fn finishFunc(...@@ -10051,7 +10141,7 @@ fn finishFunc(
10051 ret_poison: bool,10141 ret_poison: bool,
10052 bare_return_type: Type,10142 bare_return_type: Type,
10053 ret_ty_src: LazySrcLoc,10143 ret_ty_src: LazySrcLoc,
10054 cc_resolved: std.builtin.CallingConvention,10144 cc_resolved: std.builtin.NewCallingConvention,
10055 is_source_decl: bool,10145 is_source_decl: bool,
10056 ret_ty_requires_comptime: bool,10146 ret_ty_requires_comptime: bool,
10057 func_inst: Zir.Inst.Index,10147 func_inst: Zir.Inst.Index,
...@@ -10064,7 +10154,6 @@ fn finishFunc(...@@ -10064,7 +10154,6 @@ fn finishFunc(
10064 const zcu = pt.zcu;10154 const zcu = pt.zcu;
10065 const ip = &zcu.intern_pool;10155 const ip = &zcu.intern_pool;
10066 const gpa = sema.gpa;10156 const gpa = sema.gpa;
10067 const target = zcu.getTarget();
1006810157
10069 const return_type: Type = if (opt_func_index == .none or ret_poison)10158 const return_type: Type = if (opt_func_index == .none or ret_poison)
10070 bare_return_type10159 bare_return_type
...@@ -10077,7 +10166,7 @@ fn finishFunc(...@@ -10077,7 +10166,7 @@ fn finishFunc(
10077 opaque_str, return_type.fmt(pt),10166 opaque_str, return_type.fmt(pt),
10078 });10167 });
10079 }10168 }
10080 if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and10169 if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and
10081 !try sema.validateExternType(return_type, .ret_ty))10170 !try sema.validateExternType(return_type, .ret_ty))
10082 {10171 {
10083 const msg = msg: {10172 const msg = msg: {
...@@ -10134,56 +10223,50 @@ fn finishFunc(...@@ -10134,56 +10223,50 @@ fn finishFunc(
10134 }10223 }
1013510224
10136 switch (cc_resolved) {10225 switch (cc_resolved) {
10137 .Interrupt, .Signal => if (return_type.zigTypeTag(zcu) != .void and return_type.zigTypeTag(zcu) != .noreturn) {10226 .x86_64_interrupt,
10227 .x86_interrupt,
10228 .arm_interrupt,
10229 .mips64_interrupt,
10230 .mips_interrupt,
10231 .riscv64_interrupt,
10232 .riscv32_interrupt,
10233 .avr_interrupt,
10234 .csky_interrupt,
10235 .m68k_interrupt,
10236 .avr_signal,
10237 => if (return_type.zigTypeTag(zcu) != .void and return_type.zigTypeTag(zcu) != .noreturn) {
10138 return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});10238 return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
10139 },10239 },
10140 .Inline => if (is_noinline) {10240 .@"inline" => if (is_noinline) {
10141 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});10241 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'inline'", .{});
10142 },10242 },
10143 else => {},10243 else => {},
10144 }10244 }
1014510245
10146 const arch = target.cpu.arch;10246 switch (zcu.callconvSupported(cc_resolved)) {
10147 if (@as(?[]const u8, switch (cc_resolved) {10247 .ok => {},
10148 .Unspecified, .C, .Naked, .Async, .Inline => null,10248 .bad_arch => |allowed_archs| {
10149 .Interrupt => switch (arch) {10249 const ArchListFormatter = struct {
10150 .x86, .x86_64, .avr, .msp430 => null,10250 archs: []const std.Target.Cpu.Arch,
10151 else => "x86, x86_64, AVR, and MSP430",10251 pub fn format(formatter: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
10152 },10252 _ = fmt;
10153 .Signal => switch (arch) {10253 _ = options;
10154 .avr => null,10254 for (formatter.archs, 0..) |arch, i| {
10155 else => "AVR",10255 if (i != 0)
10156 },10256 try writer.writeAll(", ");
10157 .Stdcall, .Fastcall, .Thiscall => switch (arch) {10257 try writer.print("'.{s}'", .{@tagName(arch)});
10158 .x86 => null,10258 }
10159 else => "x86",10259 }
10160 },10260 };
10161 .Vectorcall => switch (arch) {10261 return sema.fail(block, cc_src, "callconv '{s}' only available on architectures {}", .{
10162 .x86, .aarch64, .aarch64_be => null,10262 @tagName(cc_resolved),
10163 else => "x86 and AArch64",10263 ArchListFormatter{ .archs = allowed_archs },
10164 },10264 });
10165 .APCS, .AAPCS, .AAPCSVFP => switch (arch) {10265 },
10166 .arm, .armeb, .aarch64, .aarch64_be, .thumb, .thumbeb => null,10266 .bad_backend => |bad_backend| return sema.fail(block, cc_src, "callconv '{s}' not supported by compiler backend '{s}'", .{
10167 else => "ARM",
10168 },
10169 .SysV, .Win64 => switch (arch) {
10170 .x86_64 => null,
10171 else => "x86_64",
10172 },
10173 .Kernel => switch (arch) {
10174 .nvptx, .nvptx64, .amdgcn, .spirv, .spirv32, .spirv64 => null,
10175 else => "nvptx, amdgcn and SPIR-V",
10176 },
10177 .Fragment, .Vertex => switch (arch) {
10178 .spirv, .spirv32, .spirv64 => null,
10179 else => "SPIR-V",
10180 },
10181 })) |allowed_platform| {
10182 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
10183 @tagName(cc_resolved),10267 @tagName(cc_resolved),
10184 allowed_platform,10268 @tagName(bad_backend),
10185 @tagName(arch),10269 }),
10186 });
10187 }10270 }
1018810271
10189 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;10272 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
...@@ -18342,10 +18425,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18342,10 +18425,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18342 } });18425 } });
1834318426
18344 const callconv_ty = try sema.getBuiltinType("CallingConvention");18427 const callconv_ty = try sema.getBuiltinType("CallingConvention");
18428 const callconv_val = Value.uninterpret(func_ty_info.cc, callconv_ty, pt) catch |err| switch (err) {
18429 error.TypeMismatch => @panic("std.builtin is corrupt"),
18430 error.OutOfMemory => |e| return e,
18431 };
1834518432
18346 const field_values = .{18433 const field_values: [5]InternPool.Index = .{
18347 // calling_convention: CallingConvention,18434 // calling_convention: CallingConvention,
18348 (try pt.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),18435 callconv_val.toIntern(),
18349 // is_generic: bool,18436 // is_generic: bool,
18350 Value.makeBool(func_ty_info.is_generic).toIntern(),18437 Value.makeBool(func_ty_info.is_generic).toIntern(),
18351 // is_var_args: bool,18438 // is_var_args: bool,
...@@ -22171,7 +22258,7 @@ fn zirReify(...@@ -22171,7 +22258,7 @@ fn zirReify(
22171 }22258 }
2217222259
22173 const is_var_args = is_var_args_val.toBool();22260 const is_var_args = is_var_args_val.toBool();
22174 const cc = zcu.toEnum(std.builtin.CallingConvention, calling_convention_val);22261 const cc = try sema.analyzeValueAsCallconv(block, src, calling_convention_val);
22175 if (is_var_args) {22262 if (is_var_args) {
22176 try sema.checkCallConvSupportsVarArgs(block, src, cc);22263 try sema.checkCallConvSupportsVarArgs(block, src, cc);
22177 }22264 }
...@@ -26657,7 +26744,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26657,7 +26744,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26657 break :blk .{ .explicit = section_name };26744 break :blk .{ .explicit = section_name };
26658 } else .default;26745 } else .default;
2665926746
26660 const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {26747 const cc: ?std.builtin.NewCallingConvention = if (extra.data.bits.has_cc_body) blk: {
26661 const body_len = sema.code.extra[extra_index];26748 const body_len = sema.code.extra[extra_index];
26662 extra_index += 1;26749 extra_index += 1;
26663 const body = sema.code.bodySlice(extra_index, body_len);26750 const body = sema.code.bodySlice(extra_index, body_len);
...@@ -26670,7 +26757,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26670,7 +26757,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26670 if (val.isGenericPoison()) {26757 if (val.isGenericPoison()) {
26671 break :blk null;26758 break :blk null;
26672 }26759 }
26673 break :blk zcu.toEnum(std.builtin.CallingConvention, val);26760 break :blk try sema.analyzeValueAsCallconv(block, cc_src, val);
26674 } else if (extra.data.bits.has_cc_ref) blk: {26761 } else if (extra.data.bits.has_cc_ref) blk: {
26675 const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);26762 const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
26676 extra_index += 1;26763 extra_index += 1;
...@@ -26689,7 +26776,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26689,7 +26776,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26689 error.GenericPoison => break :blk null,26776 error.GenericPoison => break :blk null,
26690 else => |e| return e,26777 else => |e| return e,
26691 };26778 };
26692 break :blk zcu.toEnum(std.builtin.CallingConvention, cc_val);26779 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
26693 } else cc: {26780 } else cc: {
26694 if (has_body) {26781 if (has_body) {
26695 const decl_inst = if (sema.generic_owner != .none) decl_inst: {26782 const decl_inst = if (sema.generic_owner != .none) decl_inst: {
...@@ -26705,7 +26792,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26705,7 +26792,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26705 break :cc .C;26792 break :cc .C;
26706 }26793 }
26707 }26794 }
26708 break :cc .Unspecified;26795 break :cc .auto;
26709 };26796 };
2671026797
26711 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {26798 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
...@@ -27132,9 +27219,15 @@ fn zirInComptime(...@@ -27132,9 +27219,15 @@ fn zirInComptime(
27132 return if (block.is_comptime) .bool_true else .bool_false;27219 return if (block.is_comptime) .bool_true else .bool_false;
27133}27220}
2713427221
27135fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {27222fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
27136 const pt = sema.pt;27223 const pt = sema.pt;
27224 const zcu = pt.zcu;
27225 const gpa = zcu.gpa;
27226 const ip = &zcu.intern_pool;
27227
27228 const src = block.nodeOffset(@bitCast(extended.operand));
27137 const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);27229 const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
27230
27138 const type_name = switch (value) {27231 const type_name = switch (value) {
27139 .atomic_order => "AtomicOrder",27232 .atomic_order => "AtomicOrder",
27140 .atomic_rmw_op => "AtomicRmwOp",27233 .atomic_rmw_op => "AtomicRmwOp",
...@@ -27152,21 +27245,25 @@ fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileErr...@@ -27152,21 +27245,25 @@ fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileErr
27152 // Values are handled here.27245 // Values are handled here.
27153 .calling_convention_c => {27246 .calling_convention_c => {
27154 const callconv_ty = try sema.getBuiltinType("CallingConvention");27247 const callconv_ty = try sema.getBuiltinType("CallingConvention");
27155 comptime assert(@intFromEnum(std.builtin.CallingConvention.C) == 1);27248 return try sema.namespaceLookupVal(
27156 const val = try pt.intern(.{ .enum_tag = .{27249 block,
27157 .ty = callconv_ty.toIntern(),27250 src,
27158 .int = .one_u8,27251 callconv_ty.getNamespaceIndex(zcu),
27159 } });27252 try ip.getOrPutString(gpa, pt.tid, "c", .no_embedded_nulls),
27160 return Air.internedToRef(val);27253 ) orelse @panic("std.builtin is corrupt");
27161 },27254 },
27162 .calling_convention_inline => {27255 .calling_convention_inline => {
27256 comptime assert(@typeInfo(std.builtin.NewCallingConvention.Tag).@"enum".tag_type == u8);
27163 const callconv_ty = try sema.getBuiltinType("CallingConvention");27257 const callconv_ty = try sema.getBuiltinType("CallingConvention");
27164 comptime assert(@intFromEnum(std.builtin.CallingConvention.Inline) == 4);27258 const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");
27165 const val = try pt.intern(.{ .enum_tag = .{27259 const inline_tag_val = try pt.enumValue(
27166 .ty = callconv_ty.toIntern(),27260 callconv_tag_ty,
27167 .int = .four_u8,27261 (try pt.intValue(
27168 } });27262 Type.u8,
27169 return Air.internedToRef(val);27263 @intFromEnum(std.builtin.NewCallingConvention.@"inline"),
27264 )).toIntern(),
27265 );
27266 return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
27170 },27267 },
27171 };27268 };
27172 const ty = try sema.getBuiltinType(type_name);27269 const ty = try sema.getBuiltinType(type_name);
...@@ -27353,7 +27450,7 @@ fn explainWhyTypeIsComptimeInner(...@@ -27353,7 +27450,7 @@ fn explainWhyTypeIsComptimeInner(
27353 try sema.errNote(src_loc, msg, "function is generic", .{});27450 try sema.errNote(src_loc, msg, "function is generic", .{});
27354 }27451 }
27355 switch (fn_info.cc) {27452 switch (fn_info.cc) {
27356 .Inline => try sema.errNote(src_loc, msg, "function has inline calling convention", .{}),27453 .@"inline" => try sema.errNote(src_loc, msg, "function has inline calling convention", .{}),
27357 else => {},27454 else => {},
27358 }27455 }
27359 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) {27456 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) {
...@@ -27461,13 +27558,12 @@ fn validateExternType(...@@ -27461,13 +27558,12 @@ fn validateExternType(
27461 },27558 },
27462 .@"fn" => {27559 .@"fn" => {
27463 if (position != .other) return false;27560 if (position != .other) return false;
27464 const target = zcu.getTarget();
27465 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.27561 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
27466 // The goal is to experiment with more integrated CPU/GPU code.27562 // The goal is to experiment with more integrated CPU/GPU code.
27467 if (ty.fnCallingConvention(zcu) == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) {27563 if (ty.fnCallingConvention(zcu) == .nvptx_kernel) {
27468 return true;27564 return true;
27469 }27565 }
27470 return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(zcu));27566 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
27471 },27567 },
27472 .@"enum" => {27568 .@"enum" => {
27473 return sema.validateExternType(ty.intTagType(zcu), position);27569 return sema.validateExternType(ty.intTagType(zcu), position);
...@@ -27547,9 +27643,9 @@ fn explainWhyTypeIsNotExtern(...@@ -27547,9 +27643,9 @@ fn explainWhyTypeIsNotExtern(
27547 return;27643 return;
27548 }27644 }
27549 switch (ty.fnCallingConvention(zcu)) {27645 switch (ty.fnCallingConvention(zcu)) {
27550 .Unspecified => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),27646 .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
27551 .Async => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}),27647 .@"async" => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}),
27552 .Inline => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),27648 .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),
27553 else => return,27649 else => return,
27554 }27650 }
27555 },27651 },
...@@ -30525,8 +30621,8 @@ const InMemoryCoercionResult = union(enum) {...@@ -30525,8 +30621,8 @@ const InMemoryCoercionResult = union(enum) {
30525 };30621 };
3052630622
30527 const CC = struct {30623 const CC = struct {
30528 actual: std.builtin.CallingConvention,30624 actual: std.builtin.NewCallingConvention,
30529 wanted: std.builtin.CallingConvention,30625 wanted: std.builtin.NewCallingConvention,
30530 };30626 };
3053130627
30532 const BitRange = struct {30628 const BitRange = struct {
...@@ -31176,8 +31272,8 @@ fn coerceInMemoryAllowedFns(...@@ -31176,8 +31272,8 @@ fn coerceInMemoryAllowedFns(
31176 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };31272 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
31177 }31273 }
3117831274
31179 if (dest_info.cc != src_info.cc) {31275 if (!callconvCoerceAllowed(target, src_info.cc, dest_info.cc)) {
31180 return InMemoryCoercionResult{ .fn_cc = .{31276 return .{ .fn_cc = .{
31181 .actual = src_info.cc,31277 .actual = src_info.cc,
31182 .wanted = dest_info.cc,31278 .wanted = dest_info.cc,
31183 } };31279 } };
...@@ -31250,6 +31346,44 @@ fn coerceInMemoryAllowedFns(...@@ -31250,6 +31346,44 @@ fn coerceInMemoryAllowedFns(
31250 return .ok;31346 return .ok;
31251}31347}
3125231348
31349fn callconvCoerceAllowed(
31350 target: std.Target,
31351 src_cc: std.builtin.NewCallingConvention,
31352 dest_cc: std.builtin.NewCallingConvention,
31353) bool {
31354 const Tag = std.builtin.NewCallingConvention.Tag;
31355 if (@as(Tag, src_cc) != @as(Tag, dest_cc)) return false;
31356
31357 switch (src_cc) {
31358 inline else => |src_data, tag| {
31359 const dest_data = @field(dest_cc, @tagName(tag));
31360 if (@TypeOf(src_data) != void) {
31361 const default_stack_align = target.stackAlignment();
31362 const src_stack_align = src_data.incoming_stack_alignment orelse default_stack_align;
31363 const dest_stack_align = src_data.incoming_stack_alignment orelse default_stack_align;
31364 if (dest_stack_align < src_stack_align) return false;
31365 }
31366 switch (@TypeOf(src_data)) {
31367 void, std.builtin.NewCallingConvention.CommonOptions => {},
31368 std.builtin.NewCallingConvention.X86RegparmOptions => {
31369 if (src_data.register_params != dest_data.register_params) return false;
31370 },
31371 std.builtin.NewCallingConvention.ArmInterruptOptions => {
31372 if (src_data.type != dest_data.type) return false;
31373 },
31374 std.builtin.NewCallingConvention.MipsInterruptOptions => {
31375 if (src_data.mode != dest_data.mode) return false;
31376 },
31377 std.builtin.NewCallingConvention.RiscvInterruptOptions => {
31378 if (src_data.level != dest_data.level) return false;
31379 },
31380 else => comptime unreachable,
31381 }
31382 },
31383 }
31384 return true;
31385}
31386
31253fn coerceInMemoryAllowedPtrs(31387fn coerceInMemoryAllowedPtrs(
31254 sema: *Sema,31388 sema: *Sema,
31255 block: *Block,31389 block: *Block,
...@@ -36306,7 +36440,7 @@ fn resolveInferredErrorSet(...@@ -36306,7 +36440,7 @@ fn resolveInferredErrorSet(
36306 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,36440 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
36307 // so here we can simply skip this case.36441 // so here we can simply skip this case.
36308 if (ies_func_info.return_type == .generic_poison_type) {36442 if (ies_func_info.return_type == .generic_poison_type) {
36309 assert(ies_func_info.cc == .Inline);36443 assert(ies_func_info.cc == .@"inline");
36310 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {36444 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {
36311 if (ies_func_info.is_generic) {36445 if (ies_func_info.is_generic) {
36312 return sema.failWithOwnedErrorMsg(block, msg: {36446 return sema.failWithOwnedErrorMsg(block, msg: {
src/Type.zig+10-6
...@@ -390,10 +390,14 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error...@@ -390,10 +390,14 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
390 try writer.writeAll("...");390 try writer.writeAll("...");
391 }391 }
392 try writer.writeAll(") ");392 try writer.writeAll(") ");
393 if (fn_info.cc != .Unspecified) {393 if (fn_info.cc != .auto) print_cc: {
394 try writer.writeAll("callconv(.");394 if (zcu.getTarget().defaultCCallingConvention()) |ccc| {
395 try writer.writeAll(@tagName(fn_info.cc));395 if (fn_info.cc.eql(ccc)) {
396 try writer.writeAll(") ");396 try writer.writeAll("callconv(.c) ");
397 break :print_cc;
398 }
399 }
400 try writer.print("callconv({any}) ", .{fn_info.cc});
397 }401 }
398 if (fn_info.return_type == .generic_poison_type) {402 if (fn_info.return_type == .generic_poison_type) {
399 try writer.writeAll("anytype");403 try writer.writeAll("anytype");
...@@ -791,7 +795,7 @@ pub fn fnHasRuntimeBitsInner(...@@ -791,7 +795,7 @@ pub fn fnHasRuntimeBitsInner(
791 const fn_info = zcu.typeToFunc(ty).?;795 const fn_info = zcu.typeToFunc(ty).?;
792 if (fn_info.is_generic) return false;796 if (fn_info.is_generic) return false;
793 if (fn_info.is_var_args) return true;797 if (fn_info.is_var_args) return true;
794 if (fn_info.cc == .Inline) return false;798 if (fn_info.cc == .@"inline") return false;
795 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid);799 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid);
796}800}
797801
...@@ -2489,7 +2493,7 @@ pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type {...@@ -2489,7 +2493,7 @@ pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type {
2489}2493}
24902494
2491/// Asserts the type is a function.2495/// Asserts the type is a function.
2492pub fn fnCallingConvention(ty: Type, zcu: *const Zcu) std.builtin.CallingConvention {2496pub fn fnCallingConvention(ty: Type, zcu: *const Zcu) std.builtin.NewCallingConvention {
2493 return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.cc;2497 return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.cc;
2494}2498}
24952499
src/Value.zig+160
...@@ -4490,3 +4490,163 @@ pub fn resolveLazy(...@@ -4490,3 +4490,163 @@ pub fn resolveLazy(
4490 else => return val,4490 else => return val,
4491 }4491 }
4492}4492}
4493
4494/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.
4495/// This is useful for accessing `std.builtin` structures received from comptime logic.
4496/// `val` must be fully resolved.
4497pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T {
4498 @setEvalBranchQuota(400_000);
4499
4500 const zcu = pt.zcu;
4501 const ip = &zcu.intern_pool;
4502 const ty = val.typeOf(zcu);
4503 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;
4504 if (val.isUndef(zcu)) return error.UndefinedValue;
4505
4506 return switch (@typeInfo(T)) {
4507 .type,
4508 .noreturn,
4509 .comptime_float,
4510 .comptime_int,
4511 .undefined,
4512 .null,
4513 .@"fn",
4514 .@"opaque",
4515 .enum_literal,
4516 => comptime unreachable, // comptime-only or otherwise impossible
4517
4518 .pointer,
4519 .array,
4520 .error_union,
4521 .error_set,
4522 .frame,
4523 .@"anyframe",
4524 .vector,
4525 => comptime unreachable, // unsupported
4526
4527 .void => {},
4528
4529 .bool => switch (val.toIntern()) {
4530 .bool_false => false,
4531 .bool_true => true,
4532 else => unreachable,
4533 },
4534
4535 .int => switch (ip.indexToKey(val.toIntern()).int.storage) {
4536 .lazy_align, .lazy_size => unreachable, // `val` is fully resolved
4537 inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
4538 .big_int => |big| big.to(T) catch return error.TypeMismatch,
4539 },
4540
4541 .float => val.toFloat(T, zcu),
4542
4543 .optional => |opt| if (val.optionalValue(zcu)) |unwrapped|
4544 try unwrapped.interpret(opt.child, pt)
4545 else
4546 null,
4547
4548 .@"enum" => zcu.toEnum(T, val),
4549
4550 .@"union" => |@"union"| {
4551 const union_obj = zcu.typeToUnion(ty) orelse return error.TypeMismatch;
4552 if (union_obj.field_types.len != @"union".fields.len) return error.TypeMismatch;
4553 const tag_val = val.unionTag(zcu) orelse return error.TypeMismatch;
4554 const tag = try tag_val.interpret(@"union".tag_type.?, pt);
4555 switch (tag) {
4556 inline else => |tag_comptime| {
4557 const Payload = std.meta.FieldType(T, tag_comptime);
4558 const payload = try val.unionValue(zcu).interpret(Payload, pt);
4559 return @unionInit(T, @tagName(tag_comptime), payload);
4560 },
4561 }
4562 },
4563
4564 .@"struct" => |@"struct"| {
4565 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;
4566 var result: T = undefined;
4567 inline for (@"struct".fields, 0..) |field, field_idx| {
4568 const field_val = try val.fieldValue(pt, field_idx);
4569 @field(result, field.name) = try field_val.interpret(field.type, pt);
4570 }
4571 return result;
4572 },
4573 };
4574}
4575
4576/// Given any `val` and a `Type` corresponding `@TypeOf(val)`, construct a `Value` representing it which can be used
4577/// within the compilation. This is useful for passing `std.builtin` structures in the compiler back to the compilation.
4578/// This is the inverse of `interpret`.
4579pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory, TypeMismatch }!Value {
4580 @setEvalBranchQuota(400_000);
4581
4582 const T = @TypeOf(val);
4583
4584 const zcu = pt.zcu;
4585 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;
4586
4587 return switch (@typeInfo(T)) {
4588 .type,
4589 .noreturn,
4590 .comptime_float,
4591 .comptime_int,
4592 .undefined,
4593 .null,
4594 .@"fn",
4595 .@"opaque",
4596 .enum_literal,
4597 => comptime unreachable, // comptime-only or otherwise impossible
4598
4599 .pointer,
4600 .array,
4601 .error_union,
4602 .error_set,
4603 .frame,
4604 .@"anyframe",
4605 .vector,
4606 => comptime unreachable, // unsupported
4607
4608 .void => .void,
4609
4610 .bool => if (val) .true else .false,
4611
4612 .int => try pt.intValue(ty, val),
4613
4614 .float => try pt.floatValue(ty, val),
4615
4616 .optional => if (val) |some|
4617 .fromInterned(try pt.intern(.{ .opt = .{
4618 .ty = ty.toIntern(),
4619 .val = (try uninterpret(some, ty.optionalChild(zcu), pt)).toIntern(),
4620 } }))
4621 else
4622 try pt.nullValue(ty),
4623
4624 .@"enum" => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()),
4625
4626 .@"union" => |@"union"| {
4627 const tag: @"union".tag_type.? = val;
4628 const tag_val = try uninterpret(tag, ty.unionTagType(zcu).?, pt);
4629 const field_ty = ty.unionFieldType(tag_val, zcu) orelse return error.TypeMismatch;
4630 return switch (val) {
4631 inline else => |payload| try pt.unionValue(
4632 ty,
4633 tag_val,
4634 try uninterpret(payload, field_ty, pt),
4635 ),
4636 };
4637 },
4638
4639 .@"struct" => |@"struct"| {
4640 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;
4641 var field_vals: [@"struct".fields.len]InternPool.Index = undefined;
4642 inline for (&field_vals, @"struct".fields, 0..) |*field_val, field, field_idx| {
4643 const field_ty = ty.fieldType(field_idx, zcu);
4644 field_val.* = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern();
4645 }
4646 return .fromInterned(try pt.intern(.{ .aggregate = .{
4647 .ty = ty.toIntern(),
4648 .storage = .{ .elems = &field_vals },
4649 } }));
4650 },
4651 };
4652}
src/Zcu.zig+90
...@@ -3539,3 +3539,93 @@ pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {...@@ -3539,3 +3539,93 @@ pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {
3539 zcu.intern_pool.funcSetIesResolved(func_index, .none);3539 zcu.intern_pool.funcSetIesResolved(func_index, .none);
3540 }3540 }
3541}3541}
3542
3543pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.NewCallingConvention) union(enum) {
3544 ok,
3545 bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc
3546 bad_backend: std.builtin.CompilerBackend, // value is current backend
3547} {
3548 const target = zcu.getTarget();
3549 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);
3550 switch (cc) {
3551 .auto, .@"inline" => return .ok,
3552 .@"async" => return .{ .bad_backend = backend }, // nothing supports async currently
3553 .naked => {}, // depends only on backend
3554 else => for (cc.archs()) |allowed_arch| {
3555 if (allowed_arch == target.cpu.arch) break;
3556 } else return .{ .bad_arch = cc.archs() },
3557 }
3558 const backend_ok = switch (backend) {
3559 .stage1 => unreachable,
3560 .other => unreachable,
3561 _ => unreachable,
3562
3563 .stage2_llvm => @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null,
3564 .stage2_c => ok: {
3565 if (target.defaultCCallingConvention()) |default_c| {
3566 if (cc.eql(default_c)) {
3567 break :ok true;
3568 }
3569 }
3570 break :ok switch (cc) {
3571 .x86_64_vectorcall,
3572 .x86_fastcall,
3573 .x86_thiscall,
3574 .x86_vectorcall,
3575 => |opts| opts.incoming_stack_alignment == null,
3576
3577 .x86_stdcall,
3578 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,
3579
3580 .naked => true,
3581
3582 else => false,
3583 };
3584 },
3585 .stage2_wasm => switch (cc) {
3586 .wasm_watc => |opts| opts.incoming_stack_alignment == null,
3587 else => false,
3588 },
3589 .stage2_arm => switch (cc) {
3590 .arm_aapcs => |opts| opts.incoming_stack_alignment == null,
3591 .naked => true,
3592 else => false,
3593 },
3594 .stage2_x86_64 => switch (cc) {
3595 .x86_64_sysv, .x86_64_win, .naked => true,
3596 else => false,
3597 },
3598 .stage2_aarch64 => switch (cc) {
3599 .aarch64_aapcs => |opts| opts.incoming_stack_alignment == null,
3600 .naked => true,
3601 else => false,
3602 },
3603 .stage2_x86 => switch (cc) {
3604 .x86_sysv,
3605 .x86_win,
3606 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0,
3607 .naked => true,
3608 else => false,
3609 },
3610 .stage2_riscv64 => switch (cc) {
3611 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,
3612 .naked => true,
3613 else => false,
3614 },
3615 .stage2_sparc64 => switch (cc) {
3616 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null,
3617 .naked => true,
3618 else => false,
3619 },
3620 .stage2_spirv64 => switch (cc) {
3621 .spirv_device,
3622 .spirv_kernel,
3623 .spirv_fragment,
3624 .spirv_vertex,
3625 => true,
3626 else => false,
3627 },
3628 };
3629 if (!backend_ok) return .{ .bad_backend = backend };
3630 return .ok;
3631}
src/Zcu/PerThread.zig+1-1
...@@ -2090,7 +2090,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!...@@ -2090,7 +2090,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
2090 .code = zir,2090 .code = zir,
2091 .owner = anal_unit,2091 .owner = anal_unit,
2092 .func_index = func_index,2092 .func_index = func_index,
2093 .func_is_naked = fn_ty_info.cc == .Naked,2093 .func_is_naked = fn_ty_info.cc == .naked,
2094 .fn_ret_ty = Type.fromInterned(fn_ty_info.return_type),2094 .fn_ret_ty = Type.fromInterned(fn_ty_info.return_type),
2095 .fn_ret_ty_ies = null,2095 .fn_ret_ty_ies = null,
2096 .branch_quota = @max(func.branchQuotaUnordered(ip), Sema.default_branch_quota),2096 .branch_quota = @max(func.branchQuotaUnordered(ip), Sema.default_branch_quota),
src/arch/aarch64/CodeGen.zig+5-5
...@@ -468,7 +468,7 @@ fn gen(self: *Self) !void {...@@ -468,7 +468,7 @@ fn gen(self: *Self) !void {
468 const pt = self.pt;468 const pt = self.pt;
469 const zcu = pt.zcu;469 const zcu = pt.zcu;
470 const cc = self.fn_type.fnCallingConvention(zcu);470 const cc = self.fn_type.fnCallingConvention(zcu);
471 if (cc != .Naked) {471 if (cc != .naked) {
472 // stp fp, lr, [sp, #-16]!472 // stp fp, lr, [sp, #-16]!
473 _ = try self.addInst(.{473 _ = try self.addInst(.{
474 .tag = .stp,474 .tag = .stp,
...@@ -6229,14 +6229,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6229,14 +6229,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6229 const ret_ty = fn_ty.fnReturnType(zcu);6229 const ret_ty = fn_ty.fnReturnType(zcu);
62306230
6231 switch (cc) {6231 switch (cc) {
6232 .Naked => {6232 .naked => {
6233 assert(result.args.len == 0);6233 assert(result.args.len == 0);
6234 result.return_value = .{ .unreach = {} };6234 result.return_value = .{ .unreach = {} };
6235 result.stack_byte_count = 0;6235 result.stack_byte_count = 0;
6236 result.stack_align = 1;6236 result.stack_align = 1;
6237 return result;6237 return result;
6238 },6238 },
6239 .C => {6239 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => {
6240 // ARM64 Procedure Call Standard6240 // ARM64 Procedure Call Standard
6241 var ncrn: usize = 0; // Next Core Register Number6241 var ncrn: usize = 0; // Next Core Register Number
6242 var nsaa: u32 = 0; // Next stacked argument address6242 var nsaa: u32 = 0; // Next stacked argument address
...@@ -6266,7 +6266,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6266,7 +6266,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62666266
6267 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned6267 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned
6268 // values to spread across odd-numbered registers.6268 // values to spread across odd-numbered registers.
6269 if (Type.fromInterned(ty).abiAlignment(zcu) == .@"16" and !self.target.isDarwin()) {6269 if (Type.fromInterned(ty).abiAlignment(zcu) == .@"16" and cc != .aarch64_aapcs_darwin) {
6270 // Round up NCRN to the next even number6270 // Round up NCRN to the next even number
6271 ncrn += ncrn % 2;6271 ncrn += ncrn % 2;
6272 }6272 }
...@@ -6298,7 +6298,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6298,7 +6298,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6298 result.stack_byte_count = nsaa;6298 result.stack_byte_count = nsaa;
6299 result.stack_align = 16;6299 result.stack_align = 16;
6300 },6300 },
6301 .Unspecified => {6301 .auto => {
6302 if (ret_ty.zigTypeTag(zcu) == .noreturn) {6302 if (ret_ty.zigTypeTag(zcu) == .noreturn) {
6303 result.return_value = .{ .unreach = {} };6303 result.return_value = .{ .unreach = {} };
6304 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {6304 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
src/arch/arm/CodeGen.zig+4-4
...@@ -475,7 +475,7 @@ fn gen(self: *Self) !void {...@@ -475,7 +475,7 @@ fn gen(self: *Self) !void {
475 const pt = self.pt;475 const pt = self.pt;
476 const zcu = pt.zcu;476 const zcu = pt.zcu;
477 const cc = self.fn_type.fnCallingConvention(zcu);477 const cc = self.fn_type.fnCallingConvention(zcu);
478 if (cc != .Naked) {478 if (cc != .naked) {
479 // push {fp, lr}479 // push {fp, lr}
480 const push_reloc = try self.addNop();480 const push_reloc = try self.addNop();
481481
...@@ -6196,14 +6196,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6196,14 +6196,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6196 const ret_ty = fn_ty.fnReturnType(zcu);6196 const ret_ty = fn_ty.fnReturnType(zcu);
61976197
6198 switch (cc) {6198 switch (cc) {
6199 .Naked => {6199 .naked => {
6200 assert(result.args.len == 0);6200 assert(result.args.len == 0);
6201 result.return_value = .{ .unreach = {} };6201 result.return_value = .{ .unreach = {} };
6202 result.stack_byte_count = 0;6202 result.stack_byte_count = 0;
6203 result.stack_align = 1;6203 result.stack_align = 1;
6204 return result;6204 return result;
6205 },6205 },
6206 .C => {6206 .arm_aapcs => {
6207 // ARM Procedure Call Standard, Chapter 6.56207 // ARM Procedure Call Standard, Chapter 6.5
6208 var ncrn: usize = 0; // Next Core Register Number6208 var ncrn: usize = 0; // Next Core Register Number
6209 var nsaa: u32 = 0; // Next stacked argument address6209 var nsaa: u32 = 0; // Next stacked argument address
...@@ -6254,7 +6254,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6254,7 +6254,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6254 result.stack_byte_count = nsaa;6254 result.stack_byte_count = nsaa;
6255 result.stack_align = 8;6255 result.stack_align = 8;
6256 },6256 },
6257 .Unspecified => {6257 .auto => {
6258 if (ret_ty.zigTypeTag(zcu) == .noreturn) {6258 if (ret_ty.zigTypeTag(zcu) == .noreturn) {
6259 result.return_value = .{ .unreach = {} };6259 result.return_value = .{ .unreach = {} };
6260 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {6260 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
src/arch/riscv64/CodeGen.zig+7-7
...@@ -977,7 +977,7 @@ pub fn generateLazy(...@@ -977,7 +977,7 @@ pub fn generateLazy(
977 .pt = pt,977 .pt = pt,
978 .allocator = gpa,978 .allocator = gpa,
979 .mir = mir,979 .mir = mir,
980 .cc = .Unspecified,980 .cc = .auto,
981 .src_loc = src_loc,981 .src_loc = src_loc,
982 .output_mode = comp.config.output_mode,982 .output_mode = comp.config.output_mode,
983 .link_mode = comp.config.link_mode,983 .link_mode = comp.config.link_mode,
...@@ -1036,7 +1036,7 @@ fn formatWipMir(...@@ -1036,7 +1036,7 @@ fn formatWipMir(
1036 .instructions = data.func.mir_instructions.slice(),1036 .instructions = data.func.mir_instructions.slice(),
1037 .frame_locs = data.func.frame_locs.slice(),1037 .frame_locs = data.func.frame_locs.slice(),
1038 },1038 },
1039 .cc = .Unspecified,1039 .cc = .auto,
1040 .src_loc = data.func.src_loc,1040 .src_loc = data.func.src_loc,
1041 .output_mode = comp.config.output_mode,1041 .output_mode = comp.config.output_mode,
1042 .link_mode = comp.config.link_mode,1042 .link_mode = comp.config.link_mode,
...@@ -1238,7 +1238,7 @@ fn gen(func: *Func) !void {...@@ -1238,7 +1238,7 @@ fn gen(func: *Func) !void {
1238 }1238 }
1239 }1239 }
12401240
1241 if (fn_info.cc != .Naked) {1241 if (fn_info.cc != .naked) {
1242 _ = try func.addPseudo(.pseudo_dbg_prologue_end);1242 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
12431243
1244 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);1244 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);
...@@ -4894,7 +4894,7 @@ fn genCall(...@@ -4894,7 +4894,7 @@ fn genCall(
4894 .lib => |lib| try pt.funcType(.{4894 .lib => |lib| try pt.funcType(.{
4895 .param_types = lib.param_types,4895 .param_types = lib.param_types,
4896 .return_type = lib.return_type,4896 .return_type = lib.return_type,
4897 .cc = .C,4897 .cc = func.target.defaultCCallingConvention().?,
4898 }),4898 }),
4899 };4899 };
49004900
...@@ -8289,12 +8289,12 @@ fn resolveCallingConventionValues(...@@ -8289,12 +8289,12 @@ fn resolveCallingConventionValues(
8289 const ret_ty = Type.fromInterned(fn_info.return_type);8289 const ret_ty = Type.fromInterned(fn_info.return_type);
82908290
8291 switch (cc) {8291 switch (cc) {
8292 .Naked => {8292 .naked => {
8293 assert(result.args.len == 0);8293 assert(result.args.len == 0);
8294 result.return_value = InstTracking.init(.unreach);8294 result.return_value = InstTracking.init(.unreach);
8295 result.stack_align = .@"8";8295 result.stack_align = .@"8";
8296 },8296 },
8297 .C, .Unspecified => {8297 .riscv64_lp64, .auto => {
8298 if (result.args.len > 8) {8298 if (result.args.len > 8) {
8299 return func.fail("RISC-V calling convention does not support more than 8 arguments", .{});8299 return func.fail("RISC-V calling convention does not support more than 8 arguments", .{});
8300 }8300 }
...@@ -8359,7 +8359,7 @@ fn resolveCallingConventionValues(...@@ -8359,7 +8359,7 @@ fn resolveCallingConventionValues(
83598359
8360 for (param_types, result.args) |ty, *arg| {8360 for (param_types, result.args) |ty, *arg| {
8361 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {8361 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
8362 assert(cc == .Unspecified);8362 assert(cc == .auto);
8363 arg.* = .none;8363 arg.* = .none;
8364 continue;8364 continue;
8365 }8365 }
src/arch/riscv64/Lower.zig+1-1
...@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,...@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,
6pic: bool,6pic: bool,
7allocator: Allocator,7allocator: Allocator,
8mir: Mir,8mir: Mir,
9cc: std.builtin.CallingConvention,9cc: std.builtin.NewCallingConvention,
10err_msg: ?*ErrorMsg = null,10err_msg: ?*ErrorMsg = null,
11src_loc: Zcu.LazySrcLoc,11src_loc: Zcu.LazySrcLoc,
12result_insts_len: u8 = undefined,12result_insts_len: u8 = undefined,
src/arch/sparc64/CodeGen.zig+3-3
...@@ -366,7 +366,7 @@ fn gen(self: *Self) !void {...@@ -366,7 +366,7 @@ fn gen(self: *Self) !void {
366 const pt = self.pt;366 const pt = self.pt;
367 const zcu = pt.zcu;367 const zcu = pt.zcu;
368 const cc = self.fn_type.fnCallingConvention(zcu);368 const cc = self.fn_type.fnCallingConvention(zcu);
369 if (cc != .Naked) {369 if (cc != .naked) {
370 // TODO Finish function prologue and epilogue for sparc64.370 // TODO Finish function prologue and epilogue for sparc64.
371371
372 // save %sp, stack_reserved_area, %sp372 // save %sp, stack_reserved_area, %sp
...@@ -4441,14 +4441,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)...@@ -4441,14 +4441,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)
4441 const ret_ty = fn_ty.fnReturnType(zcu);4441 const ret_ty = fn_ty.fnReturnType(zcu);
44424442
4443 switch (cc) {4443 switch (cc) {
4444 .Naked => {4444 .naked => {
4445 assert(result.args.len == 0);4445 assert(result.args.len == 0);
4446 result.return_value = .{ .unreach = {} };4446 result.return_value = .{ .unreach = {} };
4447 result.stack_byte_count = 0;4447 result.stack_byte_count = 0;
4448 result.stack_align = .@"1";4448 result.stack_align = .@"1";
4449 return result;4449 return result;
4450 },4450 },
4451 .Unspecified, .C => {4451 .auto, .sparc64_sysv => {
4452 // SPARC Compliance Definition 2.4.1, Chapter 34452 // SPARC Compliance Definition 2.4.1, Chapter 3
4453 // Low-Level System Information (64-bit psABI) - Function Calling Sequence4453 // Low-Level System Information (64-bit psABI) - Function Calling Sequence
44544454
src/arch/wasm/CodeGen.zig+18-17
...@@ -1145,7 +1145,7 @@ fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue {...@@ -1145,7 +1145,7 @@ fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue {
1145/// Memory is owned by the caller.1145/// Memory is owned by the caller.
1146fn genFunctype(1146fn genFunctype(
1147 gpa: Allocator,1147 gpa: Allocator,
1148 cc: std.builtin.CallingConvention,1148 cc: std.builtin.NewCallingConvention,
1149 params: []const InternPool.Index,1149 params: []const InternPool.Index,
1150 return_type: Type,1150 return_type: Type,
1151 pt: Zcu.PerThread,1151 pt: Zcu.PerThread,
...@@ -1160,7 +1160,7 @@ fn genFunctype(...@@ -1160,7 +1160,7 @@ fn genFunctype(
1160 if (firstParamSRet(cc, return_type, pt, target)) {1160 if (firstParamSRet(cc, return_type, pt, target)) {
1161 try temp_params.append(.i32); // memory address is always a 32-bit handle1161 try temp_params.append(.i32); // memory address is always a 32-bit handle
1162 } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {1162 } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
1163 if (cc == .C) {1163 if (cc == .wasm_watc) {
1164 const res_classes = abi.classifyType(return_type, zcu);1164 const res_classes = abi.classifyType(return_type, zcu);
1165 assert(res_classes[0] == .direct and res_classes[1] == .none);1165 assert(res_classes[0] == .direct and res_classes[1] == .none);
1166 const scalar_type = abi.scalarType(return_type, zcu);1166 const scalar_type = abi.scalarType(return_type, zcu);
...@@ -1178,7 +1178,7 @@ fn genFunctype(...@@ -1178,7 +1178,7 @@ fn genFunctype(
1178 if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;1178 if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11791179
1180 switch (cc) {1180 switch (cc) {
1181 .C => {1181 .wasm_watc => {
1182 const param_classes = abi.classifyType(param_type, zcu);1182 const param_classes = abi.classifyType(param_type, zcu);
1183 if (param_classes[1] == .none) {1183 if (param_classes[1] == .none) {
1184 if (param_classes[0] == .direct) {1184 if (param_classes[0] == .direct) {
...@@ -1367,7 +1367,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV...@@ -1367,7 +1367,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
1367 .args = &.{},1367 .args = &.{},
1368 .return_value = .none,1368 .return_value = .none,
1369 };1369 };
1370 if (cc == .Naked) return result;1370 if (cc == .naked) return result;
13711371
1372 var args = std.ArrayList(WValue).init(func.gpa);1372 var args = std.ArrayList(WValue).init(func.gpa);
1373 defer args.deinit();1373 defer args.deinit();
...@@ -1382,7 +1382,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV...@@ -1382,7 +1382,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
1382 }1382 }
13831383
1384 switch (cc) {1384 switch (cc) {
1385 .Unspecified => {1385 .auto => {
1386 for (fn_info.param_types.get(ip)) |ty| {1386 for (fn_info.param_types.get(ip)) |ty| {
1387 if (!Type.fromInterned(ty).hasRuntimeBitsIgnoreComptime(zcu)) {1387 if (!Type.fromInterned(ty).hasRuntimeBitsIgnoreComptime(zcu)) {
1388 continue;1388 continue;
...@@ -1392,7 +1392,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV...@@ -1392,7 +1392,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
1392 func.local_index += 1;1392 func.local_index += 1;
1393 }1393 }
1394 },1394 },
1395 .C => {1395 .wasm_watc => {
1396 for (fn_info.param_types.get(ip)) |ty| {1396 for (fn_info.param_types.get(ip)) |ty| {
1397 const ty_classes = abi.classifyType(Type.fromInterned(ty), zcu);1397 const ty_classes = abi.classifyType(Type.fromInterned(ty), zcu);
1398 for (ty_classes) |class| {1398 for (ty_classes) |class| {
...@@ -1408,10 +1408,11 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV...@@ -1408,10 +1408,11 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
1408 return result;1408 return result;
1409}1409}
14101410
1411fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, pt: Zcu.PerThread, target: std.Target) bool {1411fn firstParamSRet(cc: std.builtin.NewCallingConvention, return_type: Type, pt: Zcu.PerThread, target: std.Target) bool {
1412 switch (cc) {1412 switch (cc) {
1413 .Unspecified, .Inline => return isByRef(return_type, pt, target),1413 .@"inline" => unreachable,
1414 .C => {1414 .auto => return isByRef(return_type, pt, target),
1415 .wasm_watc => {
1415 const ty_classes = abi.classifyType(return_type, pt.zcu);1416 const ty_classes = abi.classifyType(return_type, pt.zcu);
1416 if (ty_classes[0] == .indirect) return true;1417 if (ty_classes[0] == .indirect) return true;
1417 if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true;1418 if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true;
...@@ -1423,8 +1424,8 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, pt: Zcu....@@ -1423,8 +1424,8 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, pt: Zcu.
14231424
1424/// Lowers a Zig type and its value based on a given calling convention to ensure1425/// Lowers a Zig type and its value based on a given calling convention to ensure
1425/// it matches the ABI.1426/// it matches the ABI.
1426fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {1427fn lowerArg(func: *CodeGen, cc: std.builtin.NewCallingConvention, ty: Type, value: WValue) !void {
1427 if (cc != .C) {1428 if (cc != .wasm_watc) {
1428 return func.lowerToStack(value);1429 return func.lowerToStack(value);
1429 }1430 }
14301431
...@@ -2108,7 +2109,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2108,7 +2109,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2108 // to the stack instead2109 // to the stack instead
2109 if (func.return_value != .none) {2110 if (func.return_value != .none) {
2110 try func.store(func.return_value, operand, ret_ty, 0);2111 try func.store(func.return_value, operand, ret_ty, 0);
2111 } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {2112 } else if (fn_info.cc == .wasm_watc and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2112 switch (ret_ty.zigTypeTag(zcu)) {2113 switch (ret_ty.zigTypeTag(zcu)) {
2113 // Aggregate types can be lowered as a singular value2114 // Aggregate types can be lowered as a singular value
2114 .@"struct", .@"union" => {2115 .@"struct", .@"union" => {
...@@ -2286,7 +2287,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2286,7 +2287,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2286 } else if (first_param_sret) {2287 } else if (first_param_sret) {
2287 break :result_value sret;2288 break :result_value sret;
2288 // TODO: Make this less fragile and optimize2289 // TODO: Make this less fragile and optimize
2289 } else if (zcu.typeToFunc(fn_ty).?.cc == .C and ret_ty.zigTypeTag(zcu) == .@"struct" or ret_ty.zigTypeTag(zcu) == .@"union") {2290 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_watc and ret_ty.zigTypeTag(zcu) == .@"struct" or ret_ty.zigTypeTag(zcu) == .@"union") {
2290 const result_local = try func.allocLocal(ret_ty);2291 const result_local = try func.allocLocal(ret_ty);
2291 try func.addLabel(.local_set, result_local.local.value);2292 try func.addLabel(.local_set, result_local.local.value);
2292 const scalar_type = abi.scalarType(ret_ty, zcu);2293 const scalar_type = abi.scalarType(ret_ty, zcu);
...@@ -2565,7 +2566,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2565,7 +2566,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2565 const arg = func.args[arg_index];2566 const arg = func.args[arg_index];
2566 const cc = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?.cc;2567 const cc = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?.cc;
2567 const arg_ty = func.typeOfIndex(inst);2568 const arg_ty = func.typeOfIndex(inst);
2568 if (cc == .C) {2569 if (cc == .wasm_watc) {
2569 const arg_classes = abi.classifyType(arg_ty, zcu);2570 const arg_classes = abi.classifyType(arg_ty, zcu);
2570 for (arg_classes) |class| {2571 for (arg_classes) |class| {
2571 if (class != .none) {2572 if (class != .none) {
...@@ -7175,12 +7176,12 @@ fn callIntrinsic(...@@ -7175,12 +7176,12 @@ fn callIntrinsic(
7175 // Always pass over C-ABI7176 // Always pass over C-ABI
7176 const pt = func.pt;7177 const pt = func.pt;
7177 const zcu = pt.zcu;7178 const zcu = pt.zcu;
7178 var func_type = try genFunctype(func.gpa, .C, param_types, return_type, pt, func.target.*);7179 var func_type = try genFunctype(func.gpa, .{ .wasm_watc = .{} }, param_types, return_type, pt, func.target.*);
7179 defer func_type.deinit(func.gpa);7180 defer func_type.deinit(func.gpa);
7180 const func_type_index = try func.bin_file.zigObjectPtr().?.putOrGetFuncType(func.gpa, func_type);7181 const func_type_index = try func.bin_file.zigObjectPtr().?.putOrGetFuncType(func.gpa, func_type);
7181 try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);7182 try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);
71827183
7183 const want_sret_param = firstParamSRet(.C, return_type, pt, func.target.*);7184 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, func.target.*);
7184 // if we want return as first param, we allocate a pointer to stack,7185 // if we want return as first param, we allocate a pointer to stack,
7185 // and emit it as our first argument7186 // and emit it as our first argument
7186 const sret = if (want_sret_param) blk: {7187 const sret = if (want_sret_param) blk: {
...@@ -7193,7 +7194,7 @@ fn callIntrinsic(...@@ -7193,7 +7194,7 @@ fn callIntrinsic(
7193 for (args, 0..) |arg, arg_i| {7194 for (args, 0..) |arg, arg_i| {
7194 assert(!(want_sret_param and arg == .stack));7195 assert(!(want_sret_param and arg == .stack));
7195 assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBitsIgnoreComptime(zcu));7196 assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBitsIgnoreComptime(zcu));
7196 try func.lowerArg(.C, Type.fromInterned(param_types[arg_i]), arg);7197 try func.lowerArg(.{ .wasm_watc = .{} }, Type.fromInterned(param_types[arg_i]), arg);
7197 }7198 }
71987199
7199 // Actually call our intrinsic7200 // Actually call our intrinsic
src/arch/x86_64/CodeGen.zig+32-33
...@@ -918,13 +918,13 @@ pub fn generate(...@@ -918,13 +918,13 @@ pub fn generate(
918 );918 );
919 function.va_info = switch (cc) {919 function.va_info = switch (cc) {
920 else => undefined,920 else => undefined,
921 .SysV => .{ .sysv = .{921 .x86_64_sysv => .{ .sysv = .{
922 .gp_count = call_info.gp_count,922 .gp_count = call_info.gp_count,
923 .fp_count = call_info.fp_count,923 .fp_count = call_info.fp_count,
924 .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count },924 .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count },
925 .reg_save_area = undefined,925 .reg_save_area = undefined,
926 } },926 } },
927 .Win64 => .{ .win64 = .{} },927 .x86_64_win => .{ .win64 = .{} },
928 };928 };
929929
930 function.gen() catch |err| switch (err) {930 function.gen() catch |err| switch (err) {
...@@ -1053,7 +1053,7 @@ pub fn generateLazy(...@@ -1053,7 +1053,7 @@ pub fn generateLazy(
1053 .bin_file = bin_file,1053 .bin_file = bin_file,
1054 .allocator = gpa,1054 .allocator = gpa,
1055 .mir = mir,1055 .mir = mir,
1056 .cc = abi.resolveCallingConvention(.Unspecified, function.target.*),1056 .cc = abi.resolveCallingConvention(.auto, function.target.*),
1057 .src_loc = src_loc,1057 .src_loc = src_loc,
1058 .output_mode = comp.config.output_mode,1058 .output_mode = comp.config.output_mode,
1059 .link_mode = comp.config.link_mode,1059 .link_mode = comp.config.link_mode,
...@@ -1159,7 +1159,7 @@ fn formatWipMir(...@@ -1159,7 +1159,7 @@ fn formatWipMir(
1159 .extra = data.self.mir_extra.items,1159 .extra = data.self.mir_extra.items,
1160 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),1160 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
1161 },1161 },
1162 .cc = .Unspecified,1162 .cc = .auto,
1163 .src_loc = data.self.src_loc,1163 .src_loc = data.self.src_loc,
1164 .output_mode = comp.config.output_mode,1164 .output_mode = comp.config.output_mode,
1165 .link_mode = comp.config.link_mode,1165 .link_mode = comp.config.link_mode,
...@@ -2023,7 +2023,7 @@ fn gen(self: *Self) InnerError!void {...@@ -2023,7 +2023,7 @@ fn gen(self: *Self) InnerError!void {
2023 const zcu = pt.zcu;2023 const zcu = pt.zcu;
2024 const fn_info = zcu.typeToFunc(self.fn_type).?;2024 const fn_info = zcu.typeToFunc(self.fn_type).?;
2025 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);2025 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
2026 if (cc != .Naked) {2026 if (cc != .naked) {
2027 try self.asmRegister(.{ ._, .push }, .rbp);2027 try self.asmRegister(.{ ._, .push }, .rbp);
2028 try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));2028 try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));
2029 try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));2029 try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));
...@@ -2056,7 +2056,7 @@ fn gen(self: *Self) InnerError!void {...@@ -2056,7 +2056,7 @@ fn gen(self: *Self) InnerError!void {
2056 }2056 }
20572057
2058 if (fn_info.is_var_args) switch (cc) {2058 if (fn_info.is_var_args) switch (cc) {
2059 .SysV => {2059 .x86_64_sysv => {
2060 const info = &self.va_info.sysv;2060 const info = &self.va_info.sysv;
2061 const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{2061 const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{
2062 .size = abi.SysV.c_abi_int_param_regs.len * 8 +2062 .size = abi.SysV.c_abi_int_param_regs.len * 8 +
...@@ -2089,7 +2089,7 @@ fn gen(self: *Self) InnerError!void {...@@ -2089,7 +2089,7 @@ fn gen(self: *Self) InnerError!void {
20892089
2090 self.performReloc(skip_sse_reloc);2090 self.performReloc(skip_sse_reloc);
2091 },2091 },
2092 .Win64 => return self.fail("TODO implement gen var arg function for Win64", .{}),2092 .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}),
2093 else => unreachable,2093 else => unreachable,
2094 };2094 };
20952095
...@@ -2541,7 +2541,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -2541,7 +2541,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2541 const enum_ty = Type.fromInterned(lazy_sym.ty);2541 const enum_ty = Type.fromInterned(lazy_sym.ty);
2542 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});2542 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
25432543
2544 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);2544 const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*);
2545 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);2545 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
2546 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);2546 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
2547 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);2547 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);
...@@ -2694,7 +2694,7 @@ fn setFrameLoc(...@@ -2694,7 +2694,7 @@ fn setFrameLoc(
2694 offset.* += self.frame_allocs.items(.abi_size)[frame_i];2694 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
2695}2695}
26962696
2697fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout {2697fn computeFrameLayout(self: *Self, cc: std.builtin.NewCallingConvention) !FrameLayout {
2698 const frame_allocs_len = self.frame_allocs.len;2698 const frame_allocs_len = self.frame_allocs.len;
2699 try self.frame_locs.resize(self.gpa, frame_allocs_len);2699 try self.frame_locs.resize(self.gpa, frame_allocs_len);
2700 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);2700 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
...@@ -3006,11 +3006,10 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -3006,11 +3006,10 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
3006 }3006 }
3007}3007}
30083008
3009pub fn spillCallerPreservedRegs(self: *Self, cc: std.builtin.CallingConvention) !void {3009pub fn spillCallerPreservedRegs(self: *Self, cc: std.builtin.NewCallingConvention) !void {
3010 switch (cc) {3010 switch (cc) {
3011 inline .SysV, .Win64 => |known_cc| try self.spillRegisters(3011 .x86_64_sysv => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_sysv = .{} })),
3012 comptime abi.getCallerPreservedRegs(known_cc),3012 .x86_64_win => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_win = .{} })),
3013 ),
3014 else => unreachable,3013 else => unreachable,
3015 }3014 }
3016}3015}
...@@ -12384,7 +12383,7 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12384,7 +12383,7 @@ fn genCall(self: *Self, info: union(enum) {
12384 .lib => |lib| try pt.funcType(.{12383 .lib => |lib| try pt.funcType(.{
12385 .param_types = lib.param_types,12384 .param_types = lib.param_types,
12386 .return_type = lib.return_type,12385 .return_type = lib.return_type,
12387 .cc = .C,12386 .cc = self.target.defaultCCallingConvention().?,
12388 }),12387 }),
12389 };12388 };
12390 const fn_info = zcu.typeToFunc(fn_ty).?;12389 const fn_info = zcu.typeToFunc(fn_ty).?;
...@@ -12543,7 +12542,7 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12543,7 +12542,7 @@ fn genCall(self: *Self, info: union(enum) {
12543 src_arg,12542 src_arg,
12544 .{},12543 .{},
12545 ),12544 ),
12546 .C, .SysV, .Win64 => {12545 .x86_64_sysv, .x86_64_win => {
12547 const promoted_ty = self.promoteInt(arg_ty);12546 const promoted_ty = self.promoteInt(arg_ty);
12548 const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu));12547 const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu));
12549 const dst_alias = registerAlias(dst_reg, promoted_abi_size);12548 const dst_alias = registerAlias(dst_reg, promoted_abi_size);
...@@ -16822,7 +16821,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -16822,7 +16821,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
16822 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;16821 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
16823 const inst_ty = self.typeOfIndex(inst);16822 const inst_ty = self.typeOfIndex(inst);
16824 const enum_ty = self.typeOf(un_op);16823 const enum_ty = self.typeOf(un_op);
16825 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);16824 const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*);
1682616825
16827 // We need a properly aligned and sized call frame to be able to call this function.16826 // We need a properly aligned and sized call frame to be able to call this function.
16828 {16827 {
...@@ -18915,7 +18914,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {...@@ -18915,7 +18914,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {
18915 self.fn_type.fnCallingConvention(zcu),18914 self.fn_type.fnCallingConvention(zcu),
18916 self.target.*,18915 self.target.*,
18917 )) {18916 )) {
18918 .SysV => result: {18917 .x86_64_sysv => result: {
18919 const info = self.va_info.sysv;18918 const info = self.va_info.sysv;
18920 const dst_fi = try self.allocFrameIndex(FrameAlloc.initSpill(va_list_ty, zcu));18919 const dst_fi = try self.allocFrameIndex(FrameAlloc.initSpill(va_list_ty, zcu));
18921 var field_off: u31 = 0;18920 var field_off: u31 = 0;
...@@ -18957,7 +18956,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {...@@ -18957,7 +18956,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {
18957 field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu));18956 field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu));
18958 break :result .{ .load_frame = .{ .index = dst_fi } };18957 break :result .{ .load_frame = .{ .index = dst_fi } };
18959 },18958 },
18960 .Win64 => return self.fail("TODO implement c_va_start for Win64", .{}),18959 .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}),
18961 else => unreachable,18960 else => unreachable,
18962 };18961 };
18963 return self.finishAir(inst, result, .{ .none, .none, .none });18962 return self.finishAir(inst, result, .{ .none, .none, .none });
...@@ -18976,7 +18975,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -18976,7 +18975,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
18976 self.fn_type.fnCallingConvention(zcu),18975 self.fn_type.fnCallingConvention(zcu),
18977 self.target.*,18976 self.target.*,
18978 )) {18977 )) {
18979 .SysV => result: {18978 .x86_64_sysv => result: {
18980 try self.spillEflagsIfOccupied();18979 try self.spillEflagsIfOccupied();
1898118980
18982 const tmp_regs =18981 const tmp_regs =
...@@ -19155,7 +19154,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -19155,7 +19154,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
19155 );19154 );
19156 break :result promote_mcv;19155 break :result promote_mcv;
19157 },19156 },
19158 .Win64 => return self.fail("TODO implement c_va_arg for Win64", .{}),19157 .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}),
19159 else => unreachable,19158 else => unreachable,
19160 };19159 };
19161 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });19160 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -19324,12 +19323,12 @@ fn resolveCallingConventionValues(...@@ -19324,12 +19323,12 @@ fn resolveCallingConventionValues(
1932419323
19325 const resolved_cc = abi.resolveCallingConvention(cc, self.target.*);19324 const resolved_cc = abi.resolveCallingConvention(cc, self.target.*);
19326 switch (cc) {19325 switch (cc) {
19327 .Naked => {19326 .naked => {
19328 assert(result.args.len == 0);19327 assert(result.args.len == 0);
19329 result.return_value = InstTracking.init(.unreach);19328 result.return_value = InstTracking.init(.unreach);
19330 result.stack_align = .@"8";19329 result.stack_align = .@"8";
19331 },19330 },
19332 .C, .SysV, .Win64 => {19331 .x86_64_sysv, .x86_64_win => {
19333 var ret_int_reg_i: u32 = 0;19332 var ret_int_reg_i: u32 = 0;
19334 var ret_sse_reg_i: u32 = 0;19333 var ret_sse_reg_i: u32 = 0;
19335 var param_int_reg_i: u32 = 0;19334 var param_int_reg_i: u32 = 0;
...@@ -19337,8 +19336,8 @@ fn resolveCallingConventionValues(...@@ -19337,8 +19336,8 @@ fn resolveCallingConventionValues(
19337 result.stack_align = .@"16";19336 result.stack_align = .@"16";
1933819337
19339 switch (resolved_cc) {19338 switch (resolved_cc) {
19340 .SysV => {},19339 .x86_64_sysv => {},
19341 .Win64 => {19340 .x86_64_win => {
19342 // Align the stack to 16bytes before allocating shadow stack space (if any).19341 // Align the stack to 16bytes before allocating shadow stack space (if any).
19343 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(zcu));19342 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(zcu));
19344 },19343 },
...@@ -19356,8 +19355,8 @@ fn resolveCallingConventionValues(...@@ -19356,8 +19355,8 @@ fn resolveCallingConventionValues(
19356 var ret_tracking_i: usize = 0;19355 var ret_tracking_i: usize = 0;
1935719356
19358 const classes = switch (resolved_cc) {19357 const classes = switch (resolved_cc) {
19359 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none),19358 .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none),
19360 .Win64 => &.{abi.classifyWindows(ret_ty, zcu)},19359 .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)},
19361 else => unreachable,19360 else => unreachable,
19362 };19361 };
19363 for (classes) |class| switch (class) {19362 for (classes) |class| switch (class) {
...@@ -19419,8 +19418,8 @@ fn resolveCallingConventionValues(...@@ -19419,8 +19418,8 @@ fn resolveCallingConventionValues(
19419 for (param_types, result.args) |ty, *arg| {19418 for (param_types, result.args) |ty, *arg| {
19420 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));19419 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
19421 switch (resolved_cc) {19420 switch (resolved_cc) {
19422 .SysV => {},19421 .x86_64_sysv => {},
19423 .Win64 => {19422 .x86_64_win => {
19424 param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i);19423 param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i);
19425 param_sse_reg_i = param_int_reg_i;19424 param_sse_reg_i = param_int_reg_i;
19426 },19425 },
...@@ -19431,8 +19430,8 @@ fn resolveCallingConventionValues(...@@ -19431,8 +19430,8 @@ fn resolveCallingConventionValues(
19431 var arg_mcv_i: usize = 0;19430 var arg_mcv_i: usize = 0;
1943219431
19433 const classes = switch (resolved_cc) {19432 const classes = switch (resolved_cc) {
19434 .SysV => mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none),19433 .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none),
19435 .Win64 => &.{abi.classifyWindows(ty, zcu)},19434 .x86_64_win => &.{abi.classifyWindows(ty, zcu)},
19436 else => unreachable,19435 else => unreachable,
19437 };19436 };
19438 for (classes) |class| switch (class) {19437 for (classes) |class| switch (class) {
...@@ -19464,11 +19463,11 @@ fn resolveCallingConventionValues(...@@ -19464,11 +19463,11 @@ fn resolveCallingConventionValues(
19464 },19463 },
19465 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),19464 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
19466 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {19465 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {
19467 .SysV => switch (class) {19466 .x86_64_sysv => switch (class) {
19468 .x87, .x87up, .complex_x87, .memory => break,19467 .x87, .x87up, .complex_x87, .memory => break,
19469 else => unreachable,19468 else => unreachable,
19470 },19469 },
19471 .Win64 => if (ty.abiSize(zcu) > 8) {19470 .x86_64_win => if (ty.abiSize(zcu) > 8) {
19472 const param_int_reg =19471 const param_int_reg =
19473 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64();19472 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64();
19474 param_int_reg_i += 1;19473 param_int_reg_i += 1;
...@@ -19530,7 +19529,7 @@ fn resolveCallingConventionValues(...@@ -19530,7 +19529,7 @@ fn resolveCallingConventionValues(
19530 assert(param_sse_reg_i <= 16);19529 assert(param_sse_reg_i <= 16);
19531 result.fp_count = param_sse_reg_i;19530 result.fp_count = param_sse_reg_i;
19532 },19531 },
19533 .Unspecified => {19532 .auto => {
19534 result.stack_align = .@"16";19533 result.stack_align = .@"16";
1953519534
19536 // Return values19535 // Return values
src/arch/x86_64/Lower.zig+1-1
...@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,...@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,
6pic: bool,6pic: bool,
7allocator: std.mem.Allocator,7allocator: std.mem.Allocator,
8mir: Mir,8mir: Mir,
9cc: std.builtin.CallingConvention,9cc: std.builtin.NewCallingConvention,
10err_msg: ?*Zcu.ErrorMsg = null,10err_msg: ?*Zcu.ErrorMsg = null,
11src_loc: Zcu.LazySrcLoc,11src_loc: Zcu.LazySrcLoc,
12result_insts_len: u8 = undefined,12result_insts_len: u8 = undefined,
src/arch/x86_64/abi.zig+23-23
...@@ -436,62 +436,62 @@ pub const Win64 = struct {...@@ -436,62 +436,62 @@ pub const Win64 = struct {
436};436};
437437
438pub fn resolveCallingConvention(438pub fn resolveCallingConvention(
439 cc: std.builtin.CallingConvention,439 cc: std.builtin.NewCallingConvention,
440 target: std.Target,440 target: std.Target,
441) std.builtin.CallingConvention {441) std.builtin.NewCallingConvention {
442 return switch (cc) {442 return switch (cc) {
443 .Unspecified, .C => switch (target.os.tag) {443 .auto => switch (target.os.tag) {
444 else => .SysV,444 else => .{ .x86_64_sysv = .{} },
445 .windows => .Win64,445 .windows => .{ .x86_64_win = .{} },
446 },446 },
447 else => cc,447 else => cc,
448 };448 };
449}449}
450450
451pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention) []const Register {451pub fn getCalleePreservedRegs(cc: std.builtin.NewCallingConvention) []const Register {
452 return switch (cc) {452 return switch (cc) {
453 .SysV => &SysV.callee_preserved_regs,453 .x86_64_sysv => &SysV.callee_preserved_regs,
454 .Win64 => &Win64.callee_preserved_regs,454 .x86_64_win => &Win64.callee_preserved_regs,
455 else => unreachable,455 else => unreachable,
456 };456 };
457}457}
458458
459pub fn getCallerPreservedRegs(cc: std.builtin.CallingConvention) []const Register {459pub fn getCallerPreservedRegs(cc: std.builtin.NewCallingConvention) []const Register {
460 return switch (cc) {460 return switch (cc) {
461 .SysV => &SysV.caller_preserved_regs,461 .x86_64_sysv => &SysV.caller_preserved_regs,
462 .Win64 => &Win64.caller_preserved_regs,462 .x86_64_win => &Win64.caller_preserved_regs,
463 else => unreachable,463 else => unreachable,
464 };464 };
465}465}
466466
467pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention) []const Register {467pub fn getCAbiIntParamRegs(cc: std.builtin.NewCallingConvention) []const Register {
468 return switch (cc) {468 return switch (cc) {
469 .SysV => &SysV.c_abi_int_param_regs,469 .x86_64_sysv => &SysV.c_abi_int_param_regs,
470 .Win64 => &Win64.c_abi_int_param_regs,470 .x86_64_win => &Win64.c_abi_int_param_regs,
471 else => unreachable,471 else => unreachable,
472 };472 };
473}473}
474474
475pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention) []const Register {475pub fn getCAbiSseParamRegs(cc: std.builtin.NewCallingConvention) []const Register {
476 return switch (cc) {476 return switch (cc) {
477 .SysV => &SysV.c_abi_sse_param_regs,477 .x86_64_sysv => &SysV.c_abi_sse_param_regs,
478 .Win64 => &Win64.c_abi_sse_param_regs,478 .x86_64_win => &Win64.c_abi_sse_param_regs,
479 else => unreachable,479 else => unreachable,
480 };480 };
481}481}
482482
483pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention) []const Register {483pub fn getCAbiIntReturnRegs(cc: std.builtin.NewCallingConvention) []const Register {
484 return switch (cc) {484 return switch (cc) {
485 .SysV => &SysV.c_abi_int_return_regs,485 .x86_64_sysv => &SysV.c_abi_int_return_regs,
486 .Win64 => &Win64.c_abi_int_return_regs,486 .x86_64_win => &Win64.c_abi_int_return_regs,
487 else => unreachable,487 else => unreachable,
488 };488 };
489}489}
490490
491pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register {491pub fn getCAbiSseReturnRegs(cc: std.builtin.NewCallingConvention) []const Register {
492 return switch (cc) {492 return switch (cc) {
493 .SysV => &SysV.c_abi_sse_return_regs,493 .x86_64_sysv => &SysV.c_abi_sse_return_regs,
494 .Win64 => &Win64.c_abi_sse_return_regs,494 .x86_64_win => &Win64.c_abi_sse_return_regs,
495 else => unreachable,495 else => unreachable,
496 };496 };
497}497}
src/codegen/c.zig+13-8
...@@ -1783,7 +1783,7 @@ pub const DeclGen = struct {...@@ -1783,7 +1783,7 @@ pub const DeclGen = struct {
1783 const fn_ctype = try dg.ctypeFromType(fn_ty, kind);1783 const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
17841784
1785 const fn_info = zcu.typeToFunc(fn_ty).?;1785 const fn_info = zcu.typeToFunc(fn_ty).?;
1786 if (fn_info.cc == .Naked) {1786 if (fn_info.cc == .naked) {
1787 switch (kind) {1787 switch (kind) {
1788 .forward => try w.writeAll("zig_naked_decl "),1788 .forward => try w.writeAll("zig_naked_decl "),
1789 .complete => try w.writeAll("zig_naked "),1789 .complete => try w.writeAll("zig_naked "),
...@@ -1796,7 +1796,7 @@ pub const DeclGen = struct {...@@ -1796,7 +1796,7 @@ pub const DeclGen = struct {
17961796
1797 var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});1797 var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
17981798
1799 if (toCallingConvention(fn_info.cc)) |call_conv| {1799 if (toCallingConvention(fn_info.cc, zcu)) |call_conv| {
1800 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });1800 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
1801 trailing = .maybe_space;1801 trailing = .maybe_space;
1802 }1802 }
...@@ -7604,12 +7604,17 @@ fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void {...@@ -7604,12 +7604,17 @@ fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void {
7604 return w.writeAll(toMemoryOrder(order));7604 return w.writeAll(toMemoryOrder(order));
7605}7605}
76067606
7607fn toCallingConvention(call_conv: std.builtin.CallingConvention) ?[]const u8 {7607fn toCallingConvention(cc: std.builtin.NewCallingConvention, zcu: *Zcu) ?[]const u8 {
7608 return switch (call_conv) {7608 return switch (cc) {
7609 .Stdcall => "stdcall",7609 .auto, .naked => null,
7610 .Fastcall => "fastcall",7610 .x86_stdcall => "stdcall",
7611 .Vectorcall => "vectorcall",7611 .x86_fastcall => "fastcall",
7612 else => null,7612 .x86_vectorcall, .x86_64_vectorcall => "vectorcall",
7613 else => {
7614 // `Zcu.callconvSupported` means this must be the C callconv.
7615 assert(cc.eql(zcu.getTarget().defaultCCallingConvention().?));
7616 return null;
7617 },
7613 };7618 };
7614}7619}
76157620
src/codegen/llvm.zig+351-243
...@@ -1159,7 +1159,7 @@ pub const Object = struct {...@@ -1159,7 +1159,7 @@ pub const Object = struct {
1159 }1159 }
11601160
1161 {1161 {
1162 var module_flags = try std.ArrayList(Builder.Metadata).initCapacity(o.gpa, 6);1162 var module_flags = try std.ArrayList(Builder.Metadata).initCapacity(o.gpa, 7);
1163 defer module_flags.deinit();1163 defer module_flags.deinit();
11641164
1165 const behavior_error = try o.builder.metadataConstant(try o.builder.intConst(.i32, 1));1165 const behavior_error = try o.builder.metadataConstant(try o.builder.intConst(.i32, 1));
...@@ -1233,6 +1233,18 @@ pub const Object = struct {...@@ -1233,6 +1233,18 @@ pub const Object = struct {
1233 }1233 }
1234 }1234 }
12351235
1236 const target = comp.root_mod.resolved_target.result;
1237 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
1238 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
1239 // v4, which is essentially a requirement on Windows. See corresponding logic in
1240 // `toLlvmCallConvTag`.
1241 module_flags.appendAssumeCapacity(try o.builder.metadataModuleFlag(
1242 behavior_max,
1243 try o.builder.metadataString("RegCallv4"),
1244 try o.builder.metadataConstant(.@"1"),
1245 ));
1246 }
1247
1236 try o.builder.metadataNamed(try o.builder.metadataString("llvm.module.flags"), module_flags.items);1248 try o.builder.metadataNamed(try o.builder.metadataString("llvm.module.flags"), module_flags.items);
1237 }1249 }
12381250
...@@ -1467,14 +1479,6 @@ pub const Object = struct {...@@ -1467,14 +1479,6 @@ pub const Object = struct {
1467 _ = try attributes.removeFnAttr(.@"noinline");1479 _ = try attributes.removeFnAttr(.@"noinline");
1468 }1480 }
14691481
1470 const stack_alignment = func.analysisUnordered(ip).stack_alignment;
1471 if (stack_alignment != .none) {
1472 try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder);
1473 try attributes.addFnAttr(.@"noinline", &o.builder);
1474 } else {
1475 _ = try attributes.removeFnAttr(.alignstack);
1476 }
1477
1478 if (func_analysis.branch_hint == .cold) {1482 if (func_analysis.branch_hint == .cold) {
1479 try attributes.addFnAttr(.cold, &o.builder);1483 try attributes.addFnAttr(.cold, &o.builder);
1480 } else {1484 } else {
...@@ -1486,7 +1490,7 @@ pub const Object = struct {...@@ -1486,7 +1490,7 @@ pub const Object = struct {
1486 } else {1490 } else {
1487 _ = try attributes.removeFnAttr(.sanitize_thread);1491 _ = try attributes.removeFnAttr(.sanitize_thread);
1488 }1492 }
1489 const is_naked = fn_info.cc == .Naked;1493 const is_naked = fn_info.cc == .naked;
1490 if (owner_mod.fuzz and !func_analysis.disable_instrumentation and !is_naked) {1494 if (owner_mod.fuzz and !func_analysis.disable_instrumentation and !is_naked) {
1491 try attributes.addFnAttr(.optforfuzzing, &o.builder);1495 try attributes.addFnAttr(.optforfuzzing, &o.builder);
1492 _ = try attributes.removeFnAttr(.skipprofile);1496 _ = try attributes.removeFnAttr(.skipprofile);
...@@ -1784,7 +1788,7 @@ pub const Object = struct {...@@ -1784,7 +1788,7 @@ pub const Object = struct {
1784 .liveness = liveness,1788 .liveness = liveness,
1785 .ng = &ng,1789 .ng = &ng,
1786 .wip = wip,1790 .wip = wip,
1787 .is_naked = fn_info.cc == .Naked,1791 .is_naked = fn_info.cc == .naked,
1788 .fuzz = fuzz,1792 .fuzz = fuzz,
1789 .ret_ptr = ret_ptr,1793 .ret_ptr = ret_ptr,
1790 .args = args.items,1794 .args = args.items,
...@@ -3038,14 +3042,33 @@ pub const Object = struct {...@@ -3038,14 +3042,33 @@ pub const Object = struct {
3038 llvm_arg_i += 1;3042 llvm_arg_i += 1;
3039 }3043 }
30403044
3041 switch (fn_info.cc) {3045 if (fn_info.cc == .@"async") {
3042 .Unspecified, .Inline => function_index.setCallConv(.fastcc, &o.builder),3046 @panic("TODO: LLVM backend lower async function");
3043 .Naked => try attributes.addFnAttr(.naked, &o.builder),3047 }
3044 .Async => {3048
3045 function_index.setCallConv(.fastcc, &o.builder);3049 {
3046 @panic("TODO: LLVM backend lower async function");3050 const cc_info = toLlvmCallConv(fn_info.cc, target).?;
3047 },3051
3048 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),3052 function_index.setCallConv(cc_info.llvm_cc, &o.builder);
3053
3054 if (cc_info.align_stack) {
3055 try attributes.addFnAttr(.{ .alignstack = .fromByteUnits(target.stackAlignment()) }, &o.builder);
3056 } else {
3057 _ = try attributes.removeFnAttr(.alignstack);
3058 }
3059
3060 if (cc_info.naked) {
3061 try attributes.addFnAttr(.naked, &o.builder);
3062 } else {
3063 _ = try attributes.removeFnAttr(.naked);
3064 }
3065
3066 for (0..cc_info.inreg_param_count) |param_idx| {
3067 try attributes.addParamAttr(param_idx, .inreg, &o.builder);
3068 }
3069 for (cc_info.inreg_param_count..std.math.maxInt(u2)) |param_idx| {
3070 _ = try attributes.removeParamAttr(param_idx, .inreg);
3071 }
3049 }3072 }
30503073
3051 if (resolved.alignment != .none)3074 if (resolved.alignment != .none)
...@@ -3061,7 +3084,7 @@ pub const Object = struct {...@@ -3061,7 +3084,7 @@ pub const Object = struct {
3061 // suppress generation of the prologue and epilogue, and the prologue is where the3084 // suppress generation of the prologue and epilogue, and the prologue is where the
3062 // frame pointer normally gets set up. At time of writing, this is the case for at3085 // frame pointer normally gets set up. At time of writing, this is the case for at
3063 // least x86 and RISC-V.3086 // least x86 and RISC-V.
3064 owner_mod.omit_frame_pointer or fn_info.cc == .Naked,3087 owner_mod.omit_frame_pointer or fn_info.cc == .naked,
3065 );3088 );
30663089
3067 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);3090 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
...@@ -4618,9 +4641,16 @@ pub const Object = struct {...@@ -4618,9 +4641,16 @@ pub const Object = struct {
4618 if (!param_ty.isPtrLikeOptional(zcu) and !ptr_info.flags.is_allowzero) {4641 if (!param_ty.isPtrLikeOptional(zcu) and !ptr_info.flags.is_allowzero) {
4619 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);4642 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4620 }4643 }
4621 if (fn_info.cc == .Interrupt) {4644 switch (fn_info.cc) {
4622 const child_type = try lowerType(o, Type.fromInterned(ptr_info.child));4645 else => {},
4623 try attributes.addParamAttr(llvm_arg_i, .{ .byval = child_type }, &o.builder);4646 .x86_64_interrupt,
4647 .x86_interrupt,
4648 .avr_interrupt,
4649 .m68k_interrupt,
4650 => {
4651 const child_type = try lowerType(o, Type.fromInterned(ptr_info.child));
4652 try attributes.addParamAttr(llvm_arg_i, .{ .byval = child_type }, &o.builder);
4653 },
4624 }4654 }
4625 if (ptr_info.flags.is_const) {4655 if (ptr_info.flags.is_const) {
4626 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);4656 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
...@@ -5677,7 +5707,7 @@ pub const FuncGen = struct {...@@ -5677,7 +5707,7 @@ pub const FuncGen = struct {
5677 .always_tail => .musttail,5707 .always_tail => .musttail,
5678 .async_kw, .no_async, .always_inline, .compile_time => unreachable,5708 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5679 },5709 },
5680 toLlvmCallConv(fn_info.cc, target),5710 toLlvmCallConvTag(fn_info.cc, target).?,
5681 try attributes.finish(&o.builder),5711 try attributes.finish(&o.builder),
5682 try o.lowerType(zig_fn_ty),5712 try o.lowerType(zig_fn_ty),
5683 llvm_fn,5713 llvm_fn,
...@@ -5756,7 +5786,7 @@ pub const FuncGen = struct {...@@ -5756,7 +5786,7 @@ pub const FuncGen = struct {
5756 _ = try fg.wip.callIntrinsicAssumeCold();5786 _ = try fg.wip.callIntrinsicAssumeCold();
5757 _ = try fg.wip.call(5787 _ = try fg.wip.call(
5758 .normal,5788 .normal,
5759 toLlvmCallConv(fn_info.cc, target),5789 toLlvmCallConvTag(fn_info.cc, target).?,
5760 .none,5790 .none,
5761 panic_global.typeOf(&o.builder),5791 panic_global.typeOf(&o.builder),
5762 panic_global.toValue(&o.builder),5792 panic_global.toValue(&o.builder),
...@@ -11554,36 +11584,146 @@ fn toLlvmAtomicRmwBinOp(...@@ -11554,36 +11584,146 @@ fn toLlvmAtomicRmwBinOp(
11554 };11584 };
11555}11585}
1155611586
11557fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {11587const CallingConventionInfo = struct {
11558 return switch (cc) {11588 /// The LLVM calling convention to use.
11559 .Unspecified, .Inline, .Async => .fastcc,11589 llvm_cc: Builder.CallConv,
11560 .C, .Naked => .ccc,11590 /// Whether to use an `alignstack` attribute to forcibly re-align the stack pointer in the function's prologue.
11561 .Stdcall => .x86_stdcallcc,11591 align_stack: bool,
11562 .Fastcall => .x86_fastcallcc,11592 /// Whether the function needs a `naked` attribute.
11563 .Vectorcall => return switch (target.cpu.arch) {11593 naked: bool,
11564 .x86, .x86_64 => .x86_vectorcallcc,11594 /// How many leading parameters to apply the `inreg` attribute to.
11565 .aarch64, .aarch64_be => .aarch64_vector_pcs,11595 inreg_param_count: u2 = 0,
11566 else => unreachable,11596};
11567 },11597
11568 .Thiscall => .x86_thiscallcc,11598pub fn toLlvmCallConv(cc: std.builtin.NewCallingConvention, target: std.Target) ?CallingConventionInfo {
11569 .APCS => .arm_apcscc,11599 const llvm_cc = toLlvmCallConvTag(cc, target) orelse return null;
11570 .AAPCS => .arm_aapcscc,11600 const incoming_stack_alignment: ?u64, const register_params: u2 = switch (cc) {
11571 .AAPCSVFP => .arm_aapcs_vfpcc,11601 inline else => |pl| switch (@TypeOf(pl)) {
11572 .Interrupt => return switch (target.cpu.arch) {11602 void => .{ null, 0 },
11573 .x86, .x86_64 => .x86_intrcc,11603 std.builtin.NewCallingConvention.CommonOptions => .{ pl.incoming_stack_alignment, 0 },
11574 .avr => .avr_intrcc,11604 std.builtin.NewCallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params },
11575 .msp430 => .msp430_intrcc,
11576 else => unreachable,
11577 },
11578 .Signal => .avr_signalcc,
11579 .SysV => .x86_64_sysvcc,
11580 .Win64 => .win64cc,
11581 .Kernel => return switch (target.cpu.arch) {
11582 .nvptx, .nvptx64 => .ptx_kernel,
11583 .amdgcn => .amdgpu_kernel,
11584 else => unreachable,11605 else => unreachable,
11585 },11606 },
11586 .Vertex, .Fragment => unreachable,11607 };
11608 return .{
11609 .llvm_cc = llvm_cc,
11610 .align_stack = if (incoming_stack_alignment) |a| need_align: {
11611 const normal_stack_align = target.stackAlignment();
11612 break :need_align a < normal_stack_align;
11613 } else false,
11614 .naked = cc == .naked,
11615 .inreg_param_count = register_params,
11616 };
11617}
11618fn toLlvmCallConvTag(cc_tag: std.builtin.NewCallingConvention.Tag, target: std.Target) ?Builder.CallConv {
11619 if (target.defaultCCallingConvention()) |default_c| {
11620 if (cc_tag == default_c) {
11621 return .ccc;
11622 }
11623 }
11624 return switch (cc_tag) {
11625 .@"inline" => unreachable,
11626 .auto, .@"async" => .fastcc,
11627 .naked => .ccc,
11628 .x86_64_sysv => .x86_64_sysvcc,
11629 .x86_64_win => .win64cc,
11630 .x86_64_regcall_v3_sysv => if (target.cpu.arch == .x86_64 and target.os.tag != .windows)
11631 .x86_regcallcc
11632 else
11633 null,
11634 .x86_64_regcall_v4_win => if (target.cpu.arch == .x86_64 and target.os.tag == .windows)
11635 .x86_regcallcc // we use the "RegCallv4" module flag to make this correct
11636 else
11637 null,
11638 .x86_64_vectorcall => .x86_vectorcallcc,
11639 .x86_64_interrupt => .x86_intrcc,
11640 .x86_stdcall => .x86_stdcallcc,
11641 .x86_fastcall => .x86_fastcallcc,
11642 .x86_thiscall => .x86_thiscallcc,
11643 .x86_regcall_v3 => if (target.cpu.arch == .x86 and target.os.tag != .windows)
11644 .x86_regcallcc
11645 else
11646 null,
11647 .x86_regcall_v4_win => if (target.cpu.arch == .x86 and target.os.tag == .windows)
11648 .x86_regcallcc // we use the "RegCallv4" module flag to make this correct
11649 else
11650 null,
11651 .x86_vectorcall => .x86_vectorcallcc,
11652 .x86_interrupt => .x86_intrcc,
11653 .aarch64_vfabi => .aarch64_vector_pcs,
11654 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,
11655 .arm_apcs => .arm_apcscc,
11656 .arm_aapcs => .arm_aapcscc,
11657 .arm_aapcs_vfp => .arm_aapcs_vfpcc,
11658 .riscv64_lp64_v => .riscv_vectorcallcc,
11659 .riscv32_ilp32_v => .riscv_vectorcallcc,
11660 .avr_builtin => .avr_builtincc,
11661 .avr_signal => .avr_signalcc,
11662 .avr_interrupt => .avr_intrcc,
11663 .m68k_rtd => .m68k_rtdcc,
11664 .m68k_interrupt => .m68k_intrcc,
11665 .amdgcn_kernel => .amdgpu_kernel,
11666 .amdgcn_cs => .amdgpu_cs,
11667 .nvptx_device => .ptx_device,
11668 .nvptx_kernel => .ptx_kernel,
11669
11670 // All the calling conventions which LLVM does not have a general representation for.
11671 // Note that these are often still supported through the `defaultCCallingConvention` path above via `ccc`.
11672 .x86_sysv,
11673 .x86_win,
11674 .x86_thiscall_mingw,
11675 .aarch64_aapcs,
11676 .aarch64_aapcs_darwin,
11677 .aarch64_aapcs_win,
11678 .arm_aapcs16_vfp,
11679 .arm_interrupt,
11680 .mips64_n64,
11681 .mips64_n32,
11682 .mips64_interrupt,
11683 .mips_o32,
11684 .mips_interrupt,
11685 .riscv64_lp64,
11686 .riscv64_interrupt,
11687 .riscv32_ilp32,
11688 .riscv32_interrupt,
11689 .sparc64_sysv,
11690 .sparc_sysv,
11691 .powerpc64_elf,
11692 .powerpc64_elf_altivec,
11693 .powerpc64_elf_v2,
11694 .powerpc_sysv,
11695 .powerpc_sysv_altivec,
11696 .powerpc_aix,
11697 .powerpc_aix_altivec,
11698 .wasm_watc,
11699 .arc_sysv,
11700 .avr_gnu,
11701 .bpf_std,
11702 .csky_sysv,
11703 .csky_interrupt,
11704 .hexagon_sysv,
11705 .hexagon_sysv_hvx,
11706 .lanai_sysv,
11707 .loongarch64_lp64,
11708 .loongarch32_ilp32,
11709 .m68k_sysv,
11710 .m68k_gnu,
11711 .msp430_eabi,
11712 .propeller1_sysv,
11713 .propeller2_sysv,
11714 .s390x_sysv,
11715 .s390x_sysv_vx,
11716 .ve_sysv,
11717 .xcore_xs1,
11718 .xcore_xs2,
11719 .xtensa_call0,
11720 .xtensa_windowed,
11721 .amdgcn_device,
11722 .spirv_device,
11723 .spirv_kernel,
11724 .spirv_fragment,
11725 .spirv_vertex,
11726 => null,
11587 };11727 };
11588}11728}
1158911729
...@@ -11711,31 +11851,27 @@ fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Targe...@@ -11711,31 +11851,27 @@ fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Targe
11711 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;11851 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
1171211852
11713 return switch (fn_info.cc) {11853 return switch (fn_info.cc) {
11714 .Unspecified, .Inline => returnTypeByRef(zcu, target, return_type),11854 .auto => returnTypeByRef(zcu, target, return_type),
11715 .C => switch (target.cpu.arch) {11855 .x86_64_sysv => firstParamSRetSystemV(return_type, zcu, target),
11716 .mips, .mipsel => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {11856 .x86_64_win => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
11717 .memory, .i32_array => true,11857 .x86_sysv, .x86_win => isByRef(return_type, zcu),
11718 .byval => false,11858 .x86_stdcall => !isScalar(zcu, return_type),
11719 },11859 .wasm_watc => wasm_c_abi.classifyType(return_type, zcu)[0] == .indirect,
11720 .x86 => isByRef(return_type, zcu),11860 .aarch64_aapcs,
11721 .x86_64 => switch (target.os.tag) {11861 .aarch64_aapcs_darwin,
11722 .windows => x86_64_abi.classifyWindows(return_type, zcu) == .memory,11862 .aarch64_aapcs_win,
11723 else => firstParamSRetSystemV(return_type, zcu, target),11863 => aarch64_c_abi.classifyType(return_type, zcu) == .memory,
11724 },11864 .arm_aapcs => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
11725 .wasm32 => wasm_c_abi.classifyType(return_type, zcu)[0] == .indirect,11865 .memory, .i64_array => true,
11726 .aarch64, .aarch64_be => aarch64_c_abi.classifyType(return_type, zcu) == .memory,11866 .i32_array => |size| size != 1,
11727 .arm, .armeb => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {11867 .byval => false,
11728 .memory, .i64_array => true,
11729 .i32_array => |size| size != 1,
11730 .byval => false,
11731 },
11732 .riscv32, .riscv64 => riscv_c_abi.classifyType(return_type, zcu) == .memory,
11733 else => false, // TODO investigate C ABI for other architectures
11734 },11868 },
11735 .SysV => firstParamSRetSystemV(return_type, zcu, target),11869 .riscv64_lp64, .riscv32_ilp32 => riscv_c_abi.classifyType(return_type, zcu) == .memory,
11736 .Win64 => x86_64_abi.classifyWindows(return_type, zcu) == .memory,11870 .mips64_n64, .mips64_n32, .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11737 .Stdcall => !isScalar(zcu, return_type),11871 .memory, .i32_array => true,
11738 else => false,11872 .byval => false,
11873 },
11874 else => false, // TODO: investigate other targets/callconvs
11739 };11875 };
11740}11876}
1174111877
...@@ -11761,82 +11897,64 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu...@@ -11761,82 +11897,64 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
11761 }11897 }
11762 const target = zcu.getTarget();11898 const target = zcu.getTarget();
11763 switch (fn_info.cc) {11899 switch (fn_info.cc) {
11764 .Unspecified,11900 .@"inline" => unreachable,
11765 .Inline,11901 .auto => return if (returnTypeByRef(zcu, target, return_type)) .void else o.lowerType(return_type),
11766 => return if (returnTypeByRef(zcu, target, return_type)) .void else o.lowerType(return_type),11902
1176711903 .x86_64_sysv => return lowerSystemVFnRetTy(o, fn_info),
11768 .C => {11904 .x86_64_win => return lowerWin64FnRetTy(o, fn_info),
11769 switch (target.cpu.arch) {11905 .x86_stdcall => return if (isScalar(zcu, return_type)) o.lowerType(return_type) else .void,
11770 .mips, .mipsel => {11906 .x86_sysv, .x86_win => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type),
11771 switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {11907 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(return_type, zcu)) {
11772 .memory, .i32_array => return .void,11908 .memory => return .void,
11773 .byval => return o.lowerType(return_type),11909 .float_array => return o.lowerType(return_type),
11774 }11910 .byval => return o.lowerType(return_type),
11775 },11911 .integer => return o.builder.intType(@intCast(return_type.bitSize(zcu))),
11776 .x86 => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type),11912 .double_integer => return o.builder.arrayType(2, .i64),
11777 .x86_64 => switch (target.os.tag) {11913 },
11778 .windows => return lowerWin64FnRetTy(o, fn_info),11914 .arm_aapcs => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
11779 else => return lowerSystemVFnRetTy(o, fn_info),11915 .memory, .i64_array => return .void,
11780 },11916 .i32_array => |len| return if (len == 1) .i32 else .void,
11781 .wasm32 => {11917 .byval => return o.lowerType(return_type),
11782 if (isScalar(zcu, return_type)) {11918 },
11783 return o.lowerType(return_type);11919 .mips64_n64, .mips64_n32, .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11784 }11920 .memory, .i32_array => return .void,
11785 const classes = wasm_c_abi.classifyType(return_type, zcu);11921 .byval => return o.lowerType(return_type),
11786 if (classes[0] == .indirect or classes[0] == .none) {11922 },
11787 return .void;11923 .riscv64_lp64, .riscv32_ilp32 => switch (riscv_c_abi.classifyType(return_type, zcu)) {
11788 }11924 .memory => return .void,
1178911925 .integer => {
11790 assert(classes[0] == .direct and classes[1] == .none);11926 return o.builder.intType(@intCast(return_type.bitSize(zcu)));
11791 const scalar_type = wasm_c_abi.scalarType(return_type, zcu);11927 },
11792 return o.builder.intType(@intCast(scalar_type.abiSize(zcu) * 8));11928 .double_integer => {
11793 },11929 return o.builder.structType(.normal, &.{ .i64, .i64 });
11794 .aarch64, .aarch64_be => {11930 },
11795 switch (aarch64_c_abi.classifyType(return_type, zcu)) {11931 .byval => return o.lowerType(return_type),
11796 .memory => return .void,11932 .fields => {
11797 .float_array => return o.lowerType(return_type),11933 var types_len: usize = 0;
11798 .byval => return o.lowerType(return_type),11934 var types: [8]Builder.Type = undefined;
11799 .integer => return o.builder.intType(@intCast(return_type.bitSize(zcu))),11935 for (0..return_type.structFieldCount(zcu)) |field_index| {
11800 .double_integer => return o.builder.arrayType(2, .i64),11936 const field_ty = return_type.fieldType(field_index, zcu);
11801 }11937 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11802 },11938 types[types_len] = try o.lowerType(field_ty);
11803 .arm, .armeb => {11939 types_len += 1;
11804 switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {11940 }
11805 .memory, .i64_array => return .void,11941 return o.builder.structType(.normal, types[0..types_len]);
11806 .i32_array => |len| return if (len == 1) .i32 else .void,11942 },
11807 .byval => return o.lowerType(return_type),11943 },
11808 }11944 .wasm_watc => {
11809 },11945 if (isScalar(zcu, return_type)) {
11810 .riscv32, .riscv64 => {11946 return o.lowerType(return_type);
11811 switch (riscv_c_abi.classifyType(return_type, zcu)) {11947 }
11812 .memory => return .void,11948 const classes = wasm_c_abi.classifyType(return_type, zcu);
11813 .integer => {11949 if (classes[0] == .indirect or classes[0] == .none) {
11814 return o.builder.intType(@intCast(return_type.bitSize(zcu)));11950 return .void;
11815 },
11816 .double_integer => {
11817 return o.builder.structType(.normal, &.{ .i64, .i64 });
11818 },
11819 .byval => return o.lowerType(return_type),
11820 .fields => {
11821 var types_len: usize = 0;
11822 var types: [8]Builder.Type = undefined;
11823 for (0..return_type.structFieldCount(zcu)) |field_index| {
11824 const field_ty = return_type.fieldType(field_index, zcu);
11825 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11826 types[types_len] = try o.lowerType(field_ty);
11827 types_len += 1;
11828 }
11829 return o.builder.structType(.normal, types[0..types_len]);
11830 },
11831 }
11832 },
11833 // TODO investigate C ABI for other architectures
11834 else => return o.lowerType(return_type),
11835 }11951 }
11952
11953 assert(classes[0] == .direct and classes[1] == .none);
11954 const scalar_type = wasm_c_abi.scalarType(return_type, zcu);
11955 return o.builder.intType(@intCast(scalar_type.abiSize(zcu) * 8));
11836 },11956 },
11837 .Win64 => return lowerWin64FnRetTy(o, fn_info),11957 // TODO investigate other callconvs
11838 .SysV => return lowerSystemVFnRetTy(o, fn_info),
11839 .Stdcall => return if (isScalar(zcu, return_type)) o.lowerType(return_type) else .void,
11840 else => return o.lowerType(return_type),11958 else => return o.lowerType(return_type),
11841 }11959 }
11842}11960}
...@@ -11989,7 +12107,8 @@ const ParamTypeIterator = struct {...@@ -11989,7 +12107,8 @@ const ParamTypeIterator = struct {
11989 return .no_bits;12107 return .no_bits;
11990 }12108 }
11991 switch (it.fn_info.cc) {12109 switch (it.fn_info.cc) {
11992 .Unspecified, .Inline => {12110 .@"inline" => unreachable,
12111 .auto => {
11993 it.zig_index += 1;12112 it.zig_index += 1;
11994 it.llvm_index += 1;12113 it.llvm_index += 1;
11995 if (ty.isSlice(zcu) or12114 if (ty.isSlice(zcu) or
...@@ -12010,97 +12129,12 @@ const ParamTypeIterator = struct {...@@ -12010,97 +12129,12 @@ const ParamTypeIterator = struct {
12010 return .byval;12129 return .byval;
12011 }12130 }
12012 },12131 },
12013 .Async => {12132 .@"async" => {
12014 @panic("TODO implement async function lowering in the LLVM backend");12133 @panic("TODO implement async function lowering in the LLVM backend");
12015 },12134 },
12016 .C => switch (target.cpu.arch) {12135 .x86_64_sysv => return it.nextSystemV(ty),
12017 .mips, .mipsel => {12136 .x86_64_win => return it.nextWin64(ty),
12018 it.zig_index += 1;12137 .x86_stdcall => {
12019 it.llvm_index += 1;
12020 switch (mips_c_abi.classifyType(ty, zcu, .arg)) {
12021 .memory => {
12022 it.byval_attr = true;
12023 return .byref;
12024 },
12025 .byval => return .byval,
12026 .i32_array => |size| return Lowering{ .i32_array = size },
12027 }
12028 },
12029 .x86_64 => switch (target.os.tag) {
12030 .windows => return it.nextWin64(ty),
12031 else => return it.nextSystemV(ty),
12032 },
12033 .wasm32 => {
12034 it.zig_index += 1;
12035 it.llvm_index += 1;
12036 if (isScalar(zcu, ty)) {
12037 return .byval;
12038 }
12039 const classes = wasm_c_abi.classifyType(ty, zcu);
12040 if (classes[0] == .indirect) {
12041 return .byref;
12042 }
12043 return .abi_sized_int;
12044 },
12045 .aarch64, .aarch64_be => {
12046 it.zig_index += 1;
12047 it.llvm_index += 1;
12048 switch (aarch64_c_abi.classifyType(ty, zcu)) {
12049 .memory => return .byref_mut,
12050 .float_array => |len| return Lowering{ .float_array = len },
12051 .byval => return .byval,
12052 .integer => {
12053 it.types_len = 1;
12054 it.types_buffer[0] = .i64;
12055 return .multiple_llvm_types;
12056 },
12057 .double_integer => return Lowering{ .i64_array = 2 },
12058 }
12059 },
12060 .arm, .armeb => {
12061 it.zig_index += 1;
12062 it.llvm_index += 1;
12063 switch (arm_c_abi.classifyType(ty, zcu, .arg)) {
12064 .memory => {
12065 it.byval_attr = true;
12066 return .byref;
12067 },
12068 .byval => return .byval,
12069 .i32_array => |size| return Lowering{ .i32_array = size },
12070 .i64_array => |size| return Lowering{ .i64_array = size },
12071 }
12072 },
12073 .riscv32, .riscv64 => {
12074 it.zig_index += 1;
12075 it.llvm_index += 1;
12076 switch (riscv_c_abi.classifyType(ty, zcu)) {
12077 .memory => return .byref_mut,
12078 .byval => return .byval,
12079 .integer => return .abi_sized_int,
12080 .double_integer => return Lowering{ .i64_array = 2 },
12081 .fields => {
12082 it.types_len = 0;
12083 for (0..ty.structFieldCount(zcu)) |field_index| {
12084 const field_ty = ty.fieldType(field_index, zcu);
12085 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12086 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);
12087 it.types_len += 1;
12088 }
12089 it.llvm_index += it.types_len - 1;
12090 return .multiple_llvm_types;
12091 },
12092 }
12093 },
12094 // TODO investigate C ABI for other architectures
12095 else => {
12096 it.zig_index += 1;
12097 it.llvm_index += 1;
12098 return .byval;
12099 },
12100 },
12101 .Win64 => return it.nextWin64(ty),
12102 .SysV => return it.nextSystemV(ty),
12103 .Stdcall => {
12104 it.zig_index += 1;12138 it.zig_index += 1;
12105 it.llvm_index += 1;12139 it.llvm_index += 1;
1210612140
...@@ -12111,6 +12145,80 @@ const ParamTypeIterator = struct {...@@ -12111,6 +12145,80 @@ const ParamTypeIterator = struct {
12111 return .byref;12145 return .byref;
12112 }12146 }
12113 },12147 },
12148 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => {
12149 it.zig_index += 1;
12150 it.llvm_index += 1;
12151 switch (aarch64_c_abi.classifyType(ty, zcu)) {
12152 .memory => return .byref_mut,
12153 .float_array => |len| return Lowering{ .float_array = len },
12154 .byval => return .byval,
12155 .integer => {
12156 it.types_len = 1;
12157 it.types_buffer[0] = .i64;
12158 return .multiple_llvm_types;
12159 },
12160 .double_integer => return Lowering{ .i64_array = 2 },
12161 }
12162 },
12163 .arm_aapcs => {
12164 it.zig_index += 1;
12165 it.llvm_index += 1;
12166 switch (arm_c_abi.classifyType(ty, zcu, .arg)) {
12167 .memory => {
12168 it.byval_attr = true;
12169 return .byref;
12170 },
12171 .byval => return .byval,
12172 .i32_array => |size| return Lowering{ .i32_array = size },
12173 .i64_array => |size| return Lowering{ .i64_array = size },
12174 }
12175 },
12176 .mips64_n64, .mips64_n32, .mips_o32 => {
12177 it.zig_index += 1;
12178 it.llvm_index += 1;
12179 switch (mips_c_abi.classifyType(ty, zcu, .arg)) {
12180 .memory => {
12181 it.byval_attr = true;
12182 return .byref;
12183 },
12184 .byval => return .byval,
12185 .i32_array => |size| return Lowering{ .i32_array = size },
12186 }
12187 },
12188 .riscv64_lp64, .riscv32_ilp32 => {
12189 it.zig_index += 1;
12190 it.llvm_index += 1;
12191 switch (riscv_c_abi.classifyType(ty, zcu)) {
12192 .memory => return .byref_mut,
12193 .byval => return .byval,
12194 .integer => return .abi_sized_int,
12195 .double_integer => return Lowering{ .i64_array = 2 },
12196 .fields => {
12197 it.types_len = 0;
12198 for (0..ty.structFieldCount(zcu)) |field_index| {
12199 const field_ty = ty.fieldType(field_index, zcu);
12200 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12201 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);
12202 it.types_len += 1;
12203 }
12204 it.llvm_index += it.types_len - 1;
12205 return .multiple_llvm_types;
12206 },
12207 }
12208 },
12209 .wasm_watc => {
12210 it.zig_index += 1;
12211 it.llvm_index += 1;
12212 if (isScalar(zcu, ty)) {
12213 return .byval;
12214 }
12215 const classes = wasm_c_abi.classifyType(ty, zcu);
12216 if (classes[0] == .indirect) {
12217 return .byref;
12218 }
12219 return .abi_sized_int;
12220 },
12221 // TODO investigate other callconvs
12114 else => {12222 else => {
12115 it.zig_index += 1;12223 it.zig_index += 1;
12116 it.llvm_index += 1;12224 it.llvm_index += 1;
...@@ -12263,13 +12371,13 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp...@@ -12263,13 +12371,13 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp
12263}12371}
1226412372
12265fn ccAbiPromoteInt(12373fn ccAbiPromoteInt(
12266 cc: std.builtin.CallingConvention,12374 cc: std.builtin.NewCallingConvention,
12267 zcu: *Zcu,12375 zcu: *Zcu,
12268 ty: Type,12376 ty: Type,
12269) ?std.builtin.Signedness {12377) ?std.builtin.Signedness {
12270 const target = zcu.getTarget();12378 const target = zcu.getTarget();
12271 switch (cc) {12379 switch (cc) {
12272 .Unspecified, .Inline, .Async => return null,12380 .auto, .@"inline", .@"async" => return null,
12273 else => {},12381 else => {},
12274 }12382 }
12275 const int_info = switch (ty.zigTypeTag(zcu)) {12383 const int_info = switch (ty.zigTypeTag(zcu)) {
src/codegen/llvm/Builder.zig+13
...@@ -2052,6 +2052,7 @@ pub const CallConv = enum(u10) {...@@ -2052,6 +2052,7 @@ pub const CallConv = enum(u10) {
2052 x86_intrcc,2052 x86_intrcc,
2053 avr_intrcc,2053 avr_intrcc,
2054 avr_signalcc,2054 avr_signalcc,
2055 avr_builtincc,
20552056
2056 amdgpu_vs = 87,2057 amdgpu_vs = 87,
2057 amdgpu_gs,2058 amdgpu_gs,
...@@ -2060,6 +2061,7 @@ pub const CallConv = enum(u10) {...@@ -2060,6 +2061,7 @@ pub const CallConv = enum(u10) {
2060 amdgpu_kernel,2061 amdgpu_kernel,
2061 x86_regcallcc,2062 x86_regcallcc,
2062 amdgpu_hs,2063 amdgpu_hs,
2064 msp430_builtincc,
20632065
2064 amdgpu_ls = 95,2066 amdgpu_ls = 95,
2065 amdgpu_es,2067 amdgpu_es,
...@@ -2068,9 +2070,15 @@ pub const CallConv = enum(u10) {...@@ -2068,9 +2070,15 @@ pub const CallConv = enum(u10) {
20682070
2069 amdgpu_gfx = 100,2071 amdgpu_gfx = 100,
20702072
2073 m68k_intrcc,
2074
2071 aarch64_sme_preservemost_from_x0 = 102,2075 aarch64_sme_preservemost_from_x0 = 102,
2072 aarch64_sme_preservemost_from_x2,2076 aarch64_sme_preservemost_from_x2,
20732077
2078 m68k_rtdcc = 106,
2079
2080 riscv_vectorcallcc = 110,
2081
2074 _,2082 _,
20752083
2076 pub const default = CallConv.ccc;2084 pub const default = CallConv.ccc;
...@@ -2115,6 +2123,7 @@ pub const CallConv = enum(u10) {...@@ -2115,6 +2123,7 @@ pub const CallConv = enum(u10) {
2115 .x86_intrcc,2123 .x86_intrcc,
2116 .avr_intrcc,2124 .avr_intrcc,
2117 .avr_signalcc,2125 .avr_signalcc,
2126 .avr_builtincc,
2118 .amdgpu_vs,2127 .amdgpu_vs,
2119 .amdgpu_gs,2128 .amdgpu_gs,
2120 .amdgpu_ps,2129 .amdgpu_ps,
...@@ -2122,13 +2131,17 @@ pub const CallConv = enum(u10) {...@@ -2122,13 +2131,17 @@ pub const CallConv = enum(u10) {
2122 .amdgpu_kernel,2131 .amdgpu_kernel,
2123 .x86_regcallcc,2132 .x86_regcallcc,
2124 .amdgpu_hs,2133 .amdgpu_hs,
2134 .msp430_builtincc,
2125 .amdgpu_ls,2135 .amdgpu_ls,
2126 .amdgpu_es,2136 .amdgpu_es,
2127 .aarch64_vector_pcs,2137 .aarch64_vector_pcs,
2128 .aarch64_sve_vector_pcs,2138 .aarch64_sve_vector_pcs,
2129 .amdgpu_gfx,2139 .amdgpu_gfx,
2140 .m68k_intrcc,
2130 .aarch64_sme_preservemost_from_x0,2141 .aarch64_sme_preservemost_from_x0,
2131 .aarch64_sme_preservemost_from_x2,2142 .aarch64_sme_preservemost_from_x2,
2143 .m68k_rtdcc,
2144 .riscv_vectorcallcc,
2132 => try writer.print(" {s}", .{@tagName(self)}),2145 => try writer.print(" {s}", .{@tagName(self)}),
2133 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),2146 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2134 }2147 }
src/codegen/spirv.zig+3-3
...@@ -1640,8 +1640,8 @@ const NavGen = struct {...@@ -1640,8 +1640,8 @@ const NavGen = struct {
16401640
1641 comptime assert(zig_call_abi_ver == 3);1641 comptime assert(zig_call_abi_ver == 3);
1642 switch (fn_info.cc) {1642 switch (fn_info.cc) {
1643 .Unspecified, .Kernel, .Fragment, .Vertex, .C => {},1643 .auto, .spirv_kernel, .spirv_fragment, .spirv_vertex => {},
1644 else => unreachable, // TODO1644 else => @panic("TODO"),
1645 }1645 }
16461646
1647 // TODO: Put this somewhere in Sema.zig1647 // TODO: Put this somewhere in Sema.zig
...@@ -2970,7 +2970,7 @@ const NavGen = struct {...@@ -2970,7 +2970,7 @@ const NavGen = struct {
2970 .id_result_type = return_ty_id,2970 .id_result_type = return_ty_id,
2971 .id_result = result_id,2971 .id_result = result_id,
2972 .function_control = switch (fn_info.cc) {2972 .function_control = switch (fn_info.cc) {
2973 .Inline => .{ .Inline = true },2973 .@"inline" => .{ .Inline = true },
2974 else => .{},2974 else => .{},
2975 },2975 },
2976 .function_type = prototype_ty_id,2976 .function_type = prototype_ty_id,
src/link/C.zig+1-1
...@@ -217,7 +217,7 @@ pub fn updateFunc(...@@ -217,7 +217,7 @@ pub fn updateFunc(
217 .mod = zcu.navFileScope(func.owner_nav).mod,217 .mod = zcu.navFileScope(func.owner_nav).mod,
218 .error_msg = null,218 .error_msg = null,
219 .pass = .{ .nav = func.owner_nav },219 .pass = .{ .nav = func.owner_nav },
220 .is_naked_fn = zcu.navValue(func.owner_nav).typeOf(zcu).fnCallingConvention(zcu) == .Naked,220 .is_naked_fn = zcu.navValue(func.owner_nav).typeOf(zcu).fnCallingConvention(zcu) == .naked,
221 .fwd_decl = fwd_decl.toManaged(gpa),221 .fwd_decl = fwd_decl.toManaged(gpa),
222 .ctype_pool = ctype_pool.*,222 .ctype_pool = ctype_pool.*,
223 .scratch = .{},223 .scratch = .{},
src/link/Coff.zig+7-5
...@@ -1484,14 +1484,16 @@ pub fn updateExports(...@@ -1484,14 +1484,16 @@ pub fn updateExports(
1484 const exported_nav = ip.getNav(exported_nav_index);1484 const exported_nav = ip.getNav(exported_nav_index);
1485 const exported_ty = exported_nav.typeOf(ip);1485 const exported_ty = exported_nav.typeOf(ip);
1486 if (!ip.isFunctionType(exported_ty)) continue;1486 if (!ip.isFunctionType(exported_ty)) continue;
1487 const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) {1487 const c_cc = target.defaultCCallingConvention().?;
1488 .x86 => .Stdcall,1488 const winapi_cc: std.builtin.NewCallingConvention = switch (target.cpu.arch) {
1489 else => .C,1489 .x86 => .{ .x86_stdcall = .{} },
1490 else => c_cc,
1490 };1491 };
1491 const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(zcu);1492 const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(zcu);
1492 if (exported_cc == .C and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {1493 const CcTag = std.builtin.NewCallingConvention.Tag;
1494 if (@as(CcTag, exported_cc) == @as(CcTag, c_cc) and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {
1493 zcu.stage1_flags.have_c_main = true;1495 zcu.stage1_flags.have_c_main = true;
1494 } else if (exported_cc == winapi_cc and target.os.tag == .windows) {1496 } else if (@as(CcTag, exported_cc) == @as(CcTag, winapi_cc) and target.os.tag == .windows) {
1495 if (exp.opts.name.eqlSlice("WinMain", ip)) {1497 if (exp.opts.name.eqlSlice("WinMain", ip)) {
1496 zcu.stage1_flags.have_winmain = true;1498 zcu.stage1_flags.have_winmain = true;
1497 } else if (exp.opts.name.eqlSlice("wWinMain", ip)) {1499 } else if (exp.opts.name.eqlSlice("wWinMain", ip)) {
src/link/Dwarf.zig+62-15
...@@ -3398,21 +3398,68 @@ fn updateType(...@@ -3398,21 +3398,68 @@ fn updateType(
3398 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;3398 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
3399 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);3399 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
3400 try wip_nav.strp(name);3400 try wip_nav.strp(name);
3401 try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {3401 const cc: DW.CC = cc: {
3402 .Unspecified, .C => .normal,3402 if (zcu.getTarget().defaultCCallingConvention()) |cc| {
3403 .Naked, .Async, .Inline => .nocall,3403 if (@as(std.builtin.NewCallingConvention.Tag, cc) == func_type.cc) {
3404 .Interrupt, .Signal => .nocall,3404 break :cc .normal;
3405 .Stdcall => .BORLAND_stdcall,3405 }
3406 .Fastcall => .BORLAND_fastcall,3406 }
3407 .Vectorcall => .LLVM_vectorcall,3407 break :cc switch (func_type.cc) {
3408 .Thiscall => .BORLAND_thiscall,3408 .@"inline" => unreachable,
3409 .APCS => .nocall,3409 .@"async", .auto, .naked => .normal,
3410 .AAPCS => .LLVM_AAPCS,3410 .x86_64_sysv => .LLVM_X86_64SysV,
3411 .AAPCSVFP => .LLVM_AAPCS_VFP,3411 .x86_64_win => .LLVM_Win64,
3412 .SysV => .LLVM_X86_64SysV,3412 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
3413 .Win64 => .LLVM_Win64,3413 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
3414 .Kernel, .Fragment, .Vertex => .nocall,3414 .x86_64_vectorcall => .LLVM_vectorcall,
3415 })));3415 .x86_sysv => .nocall,
3416 .x86_win => .nocall,
3417 .x86_stdcall => .BORLAND_stdcall,
3418 .x86_fastcall => .BORLAND_msfastcall,
3419 .x86_thiscall => .BORLAND_thiscall,
3420 .x86_thiscall_mingw => .BORLAND_thiscall,
3421 .x86_regcall_v3 => .LLVM_X86RegCall,
3422 .x86_regcall_v4_win => .LLVM_X86RegCall,
3423 .x86_vectorcall => .LLVM_vectorcall,
3424
3425 .aarch64_aapcs => .LLVM_AAPCS,
3426 .aarch64_aapcs_darwin => .LLVM_AAPCS,
3427 .aarch64_aapcs_win => .LLVM_AAPCS,
3428 .aarch64_vfabi => .LLVM_AAPCS,
3429 .aarch64_vfabi_sve => .LLVM_AAPCS,
3430
3431 .arm_apcs => .nocall,
3432 .arm_aapcs => .LLVM_AAPCS,
3433 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
3434 .arm_aapcs16_vfp => .nocall,
3435
3436 .riscv64_lp64_v,
3437 .riscv32_ilp32_v,
3438 => .LLVM_RISCVVectorCall,
3439
3440 .m68k_rtd => .LLVM_M68kRTD,
3441
3442 .amdgcn_kernel,
3443 .nvptx_kernel,
3444 .spirv_kernel,
3445 => .LLVM_OpenCLKernel,
3446
3447 .x86_64_interrupt,
3448 .x86_interrupt,
3449 .arm_interrupt,
3450 .mips64_interrupt,
3451 .mips_interrupt,
3452 .riscv64_interrupt,
3453 .riscv32_interrupt,
3454 .avr_interrupt,
3455 .csky_interrupt,
3456 .m68k_interrupt,
3457 => .normal,
3458
3459 else => .nocall,
3460 };
3461 };
3462 try diw.writeByte(@intFromEnum(cc));
3416 try wip_nav.refType(Type.fromInterned(func_type.return_type));3463 try wip_nav.refType(Type.fromInterned(func_type.return_type));
3417 for (0..func_type.param_types.len) |param_index| {3464 for (0..func_type.param_types.len) |param_index| {
3418 try wip_nav.abbrevCode(.func_type_param);3465 try wip_nav.abbrevCode(.func_type_param);
src/link/SpirV.zig+3-4
...@@ -165,10 +165,9 @@ pub fn updateExports(...@@ -165,10 +165,9 @@ pub fn updateExports(
165 const target = zcu.getTarget();165 const target = zcu.getTarget();
166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
167 const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {167 const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {
168 .Vertex => spec.ExecutionModel.Vertex,168 .spirv_vertex => spec.ExecutionModel.Vertex,
169 .Fragment => spec.ExecutionModel.Fragment,169 .spirv_fragment => spec.ExecutionModel.Fragment,
170 .Kernel => spec.ExecutionModel.Kernel,170 .spirv_kernel => spec.ExecutionModel.Kernel,
171 .C => return, // TODO: What to do here?
172 else => unreachable,171 else => unreachable,
173 };172 };
174 const is_vulkan = target.os.tag == .vulkan;173 const is_vulkan = target.os.tag == .vulkan;
src/target.zig+3-3
...@@ -544,13 +544,13 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 {...@@ -544,13 +544,13 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 {
544 };544 };
545}545}
546546
547pub fn fnCallConvAllowsZigTypes(target: std.Target, cc: std.builtin.CallingConvention) bool {547pub fn fnCallConvAllowsZigTypes(cc: std.builtin.NewCallingConvention) bool {
548 return switch (cc) {548 return switch (cc) {
549 .Unspecified, .Async, .Inline => true,549 .auto, .@"async", .@"inline" => true,
550 // For now we want to authorize PTX kernel to use zig objects, even if550 // For now we want to authorize PTX kernel to use zig objects, even if
551 // we end up exposing the ABI. The goal is to experiment with more551 // we end up exposing the ABI. The goal is to experiment with more
552 // integrated CPU/GPU code.552 // integrated CPU/GPU code.
553 .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64,553 .nvptx_kernel => true,
554 else => false,554 else => false,
555 };555 };
556}556}
src/translate_c.zig+14-14
...@@ -4,7 +4,6 @@ const assert = std.debug.assert;...@@ -4,7 +4,6 @@ const assert = std.debug.assert;
4const mem = std.mem;4const mem = std.mem;
5const math = std.math;5const math = std.math;
6const meta = std.meta;6const meta = std.meta;
7const CallingConvention = std.builtin.CallingConvention;
8const clang = @import("clang.zig");7const clang = @import("clang.zig");
9const aro = @import("aro");8const aro = @import("aro");
10const CToken = aro.Tokenizer.Token;9const CToken = aro.Tokenizer.Token;
...@@ -5001,17 +5000,18 @@ fn transCC(...@@ -5001,17 +5000,18 @@ fn transCC(
5001 c: *Context,5000 c: *Context,
5002 fn_ty: *const clang.FunctionType,5001 fn_ty: *const clang.FunctionType,
5003 source_loc: clang.SourceLocation,5002 source_loc: clang.SourceLocation,
5004) !CallingConvention {5003) !ast.Payload.Func.CallingConvention {
5005 const clang_cc = fn_ty.getCallConv();5004 const clang_cc = fn_ty.getCallConv();
5006 switch (clang_cc) {5005 return switch (clang_cc) {
5007 .C => return CallingConvention.C,5006 .C => .c,
5008 .X86StdCall => return CallingConvention.Stdcall,5007 .X86_64SysV => .x86_64_sysv,
5009 .X86FastCall => return CallingConvention.Fastcall,5008 .X86StdCall => .x86_stdcall,
5010 .X86VectorCall, .AArch64VectorCall => return CallingConvention.Vectorcall,5009 .X86FastCall => .x86_fastcall,
5011 .X86ThisCall => return CallingConvention.Thiscall,5010 .X86ThisCall => .x86_thiscall,
5012 .AAPCS => return CallingConvention.AAPCS,5011 .X86VectorCall => .x86_vectorcall,
5013 .AAPCS_VFP => return CallingConvention.AAPCSVFP,5012 .AArch64VectorCall => .aarch64_vfabi,
5014 .X86_64SysV => return CallingConvention.SysV,5013 .AAPCS => .arm_aapcs,
5014 .AAPCS_VFP => .arm_aapcs_vfp,
5015 else => return fail(5015 else => return fail(
5016 c,5016 c,
5017 error.UnsupportedType,5017 error.UnsupportedType,
...@@ -5019,7 +5019,7 @@ fn transCC(...@@ -5019,7 +5019,7 @@ fn transCC(
5019 "unsupported calling convention: {s}",5019 "unsupported calling convention: {s}",
5020 .{@tagName(clang_cc)},5020 .{@tagName(clang_cc)},
5021 ),5021 ),
5022 }5022 };
5023}5023}
50245024
5025fn transFnProto(5025fn transFnProto(
...@@ -5056,7 +5056,7 @@ fn finishTransFnProto(...@@ -5056,7 +5056,7 @@ fn finishTransFnProto(
5056 source_loc: clang.SourceLocation,5056 source_loc: clang.SourceLocation,
5057 fn_decl_context: ?FnDeclContext,5057 fn_decl_context: ?FnDeclContext,
5058 is_var_args: bool,5058 is_var_args: bool,
5059 cc: CallingConvention,5059 cc: ast.Payload.Func.CallingConvention,
5060 is_pub: bool,5060 is_pub: bool,
5061) !*ast.Payload.Func {5061) !*ast.Payload.Func {
5062 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;5062 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
...@@ -5104,7 +5104,7 @@ fn finishTransFnProto(...@@ -5104,7 +5104,7 @@ fn finishTransFnProto(
51045104
5105 const alignment = if (fn_decl) |decl| ClangAlignment.forFunc(c, decl).zigAlignment() else null;5105 const alignment = if (fn_decl) |decl| ClangAlignment.forFunc(c, decl).zigAlignment() else null;
51065106
5107 const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .C) null else cc;5107 const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .c) null else cc;
51085108
5109 const return_type_node = blk: {5109 const return_type_node = blk: {
5110 if (fn_ty.getNoReturnAttr()) {5110 if (fn_ty.getNoReturnAttr()) {