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 {
550550 is_var_args: bool,
551551 name: ?[]const u8,
552552 linksection_string: ?[]const u8,
553 explicit_callconv: ?std.builtin.CallingConvention,
553 explicit_callconv: ?CallingConvention,
554554 params: []Param,
555555 return_type: Node,
556556 body: ?Node,
557557 alignment: ?c_uint,
558558 },
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 };
559571 };
560572
561573 pub const Param = struct {
......@@ -2812,14 +2824,50 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
28122824 const callconv_expr = if (payload.explicit_callconv) |some| blk: {
28132825 _ = try c.addToken(.keyword_callconv, "callconv");
28142826 _ = try c.addToken(.l_paren, "(");
2815 _ = try c.addToken(.period, ".");
2816 const res = try c.addNode(.{
2817 .tag = .enum_literal,
2818 .main_token = try c.addTokenFmt(.identifier, "{s}", .{@tagName(some)}),
2819 .data = undefined,
2820 });
2827 const cc_node = switch (some) {
2828 .c => cc_node: {
2829 _ = try c.addToken(.period, ".");
2830 break :cc_node try c.addNode(.{
2831 .tag = .enum_literal,
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 };
28212869 _ = try c.addToken(.r_paren, ")");
2822 break :blk res;
2870 break :blk cc_node;
28232871 } else 0;
28242872
28252873 const return_type_expr = try renderNode(c, payload.return_type);
lib/std/Target.zig+223
......@@ -1609,6 +1609,165 @@ pub const Cpu = struct {
16091609 else => ".X",
16101610 };
16111611 }
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 }
16121771 };
16131772
16141773 pub const Model = struct {
......@@ -2873,6 +3032,70 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
28733032 );
28743033}
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
28763099pub fn osArchName(target: std.Target) [:0]const u8 {
28773100 return target.os.tag.archName(target.cpu.arch);
28783101}
lib/std/builtin.zig+330
......@@ -210,6 +210,336 @@ pub const CallingConvention = enum(u8) {
210210 Vertex,
211211};
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
213543/// This data structure is used by the Zig language code generation and
214544/// therefore must be kept in sync with the compiler implementation.
215545pub const AddressSpace = enum(u5) {
src/InternPool.zig+92-13
......@@ -1988,7 +1988,7 @@ pub const Key = union(enum) {
19881988 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper
19891989 /// method for accessing this.
19901990 noalias_bits: u32,
1991 cc: std.builtin.CallingConvention,
1991 cc: std.builtin.NewCallingConvention,
19921992 is_var_args: bool,
19931993 is_generic: bool,
19941994 is_noinline: bool,
......@@ -2011,10 +2011,10 @@ pub const Key = union(enum) {
20112011 a.return_type == b.return_type and
20122012 a.comptime_bits == b.comptime_bits and
20132013 a.noalias_bits == b.noalias_bits and
2014 a.cc == b.cc and
20152014 a.is_var_args == b.is_var_args and
20162015 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);
20182018 }
20192019
20202020 pub fn hash(self: FuncType, hasher: *Hash, ip: *const InternPool) void {
......@@ -5444,7 +5444,7 @@ pub const Tag = enum(u8) {
54445444 flags: Flags,
54455445
54465446 pub const Flags = packed struct(u32) {
5447 cc: std.builtin.CallingConvention,
5447 cc: PackedCallingConvention,
54485448 is_var_args: bool,
54495449 is_generic: bool,
54505450 has_comptime_bits: bool,
......@@ -5453,7 +5453,7 @@ pub const Tag = enum(u8) {
54535453 cc_is_generic: bool,
54545454 section_is_generic: bool,
54555455 addrspace_is_generic: bool,
5456 _: u16 = 0,
5456 _: u6 = 0,
54575457 };
54585458 };
54595459
......@@ -6912,7 +6912,7 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke
69126912 .return_type = type_function.data.return_type,
69136913 .comptime_bits = comptime_bits,
69146914 .noalias_bits = noalias_bits,
6915 .cc = type_function.data.flags.cc,
6915 .cc = type_function.data.flags.cc.unpack(),
69166916 .is_var_args = type_function.data.flags.is_var_args,
69176917 .is_noinline = type_function.data.flags.is_noinline,
69186918 .cc_is_generic = type_function.data.flags.cc_is_generic,
......@@ -8526,7 +8526,7 @@ pub const GetFuncTypeKey = struct {
85268526 comptime_bits: u32 = 0,
85278527 noalias_bits: u32 = 0,
85288528 /// `null` means generic.
8529 cc: ?std.builtin.CallingConvention = .Unspecified,
8529 cc: ?std.builtin.NewCallingConvention = .auto,
85308530 is_var_args: bool = false,
85318531 is_generic: bool = false,
85328532 is_noinline: bool = false,
......@@ -8564,7 +8564,7 @@ pub fn getFuncType(
85648564 .params_len = params_len,
85658565 .return_type = key.return_type,
85668566 .flags = .{
8567 .cc = key.cc orelse .Unspecified,
8567 .cc = .pack(key.cc orelse .auto),
85688568 .is_var_args = key.is_var_args,
85698569 .has_comptime_bits = key.comptime_bits != 0,
85708570 .has_noalias_bits = key.noalias_bits != 0,
......@@ -8668,7 +8668,7 @@ pub const GetFuncDeclKey = struct {
86688668 rbrace_line: u32,
86698669 lbrace_column: u32,
86708670 rbrace_column: u32,
8671 cc: ?std.builtin.CallingConvention,
8671 cc: ?std.builtin.NewCallingConvention,
86728672 is_noinline: bool,
86738673};
86748674
......@@ -8733,7 +8733,7 @@ pub const GetFuncDeclIesKey = struct {
87338733 comptime_bits: u32,
87348734 bare_return_type: Index,
87358735 /// null means generic.
8736 cc: ?std.builtin.CallingConvention,
8736 cc: ?std.builtin.NewCallingConvention,
87378737 /// null means generic.
87388738 alignment: ?Alignment,
87398739 section_is_generic: bool,
......@@ -8818,7 +8818,7 @@ pub fn getFuncDeclIes(
88188818 .params_len = params_len,
88198819 .return_type = error_union_type,
88208820 .flags = .{
8821 .cc = key.cc orelse .Unspecified,
8821 .cc = .pack(key.cc orelse .auto),
88228822 .is_var_args = key.is_var_args,
88238823 .has_comptime_bits = key.comptime_bits != 0,
88248824 .has_noalias_bits = key.noalias_bits != 0,
......@@ -8948,7 +8948,7 @@ pub const GetFuncInstanceKey = struct {
89488948 comptime_args: []const Index,
89498949 noalias_bits: u32,
89508950 bare_return_type: Index,
8951 cc: std.builtin.CallingConvention,
8951 cc: std.builtin.NewCallingConvention,
89528952 alignment: Alignment,
89538953 section: OptionalNullTerminatedString,
89548954 is_noinline: bool,
......@@ -9110,7 +9110,7 @@ pub fn getFuncInstanceIes(
91109110 .params_len = params_len,
91119111 .return_type = error_union_type,
91129112 .flags = .{
9113 .cc = arg.cc,
9113 .cc = .pack(arg.cc),
91149114 .is_var_args = false,
91159115 .has_comptime_bits = false,
91169116 .has_noalias_bits = arg.noalias_bits != 0,
......@@ -12224,3 +12224,82 @@ pub fn getErrorValue(
1222412224pub fn getErrorValueIfExists(ip: *const InternPool, name: NullTerminatedString) ?Zcu.ErrorInt {
1222512225 return @intFromEnum(ip.global_error_set.getErrorValueIfExists(name) orelse return null);
1222612226}
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,
2626/// in the case of an inline or comptime function call.
2727/// This could be `none`, a `func_decl`, or a `func_instance`.
2828func_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`.
3030func_is_naked: bool,
3131/// Used to restore the error return trace when returning a non-error from a function.
3232error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
......@@ -1355,7 +1355,7 @@ fn analyzeBodyInner(
13551355 },
13561356 .value_placeholder => unreachable, // never appears in a body
13571357 .field_parent_ptr => try sema.zirFieldParentPtr(block, extended),
1358 .builtin_value => try sema.zirBuiltinValue(extended),
1358 .builtin_value => try sema.zirBuiltinValue(block, extended),
13591359 .inplace_arith_result_ty => try sema.zirInplaceArithResultTy(extended),
13601360 };
13611361 },
......@@ -2698,6 +2698,20 @@ fn analyzeAsInt(
26982698 return try val.toUnsignedIntSema(sema.pt);
26992699}
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
27012715/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
27022716/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
27032717fn 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
65166530 }
65176531
65186532 switch (Value.fromInterned(func).typeOf(zcu).fnCallingConvention(zcu)) {
6519 .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
6520 .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
6533 .naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
6534 .@"inline" => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
65216535 else => {},
65226536 }
65236537
......@@ -7554,7 +7568,7 @@ fn analyzeCall(
75547568 if (try sema.resolveValue(func)) |func_val|
75557569 if (func_val.isUndef(zcu))
75567570 return sema.failWithUseOfUndef(block, call_src);
7557 if (cc == .Naked) {
7571 if (cc == .naked) {
75587572 const maybe_func_inst = try sema.funcDeclSrcInst(func);
75597573 const msg = msg: {
75607574 const msg = try sema.errMsg(
......@@ -7587,7 +7601,7 @@ fn analyzeCall(
75877601 .async_kw => return sema.failWithUseOfAsync(block, call_src),
75887602 };
75897603
7590 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
7604 if (modifier == .never_inline and func_ty_info.cc == .@"inline") {
75917605 return sema.fail(block, call_src, "'never_inline' call of inline function", .{});
75927606 }
75937607 if (modifier == .always_inline and func_ty_info.is_noinline) {
......@@ -7598,7 +7612,7 @@ fn analyzeCall(
75987612
75997613 const is_generic_call = func_ty_info.is_generic;
76007614 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";
76027616 var comptime_reason: ?*const Block.ComptimeReason = null;
76037617 if (!is_inline_call and !is_comptime_call) {
76047618 if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {
......@@ -8455,7 +8469,7 @@ fn instantiateGenericCall(
84558469 }
84568470 // Similarly, if the call evaluated to a generic type we need to instead
84578471 // 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") {
84598473 return error.GenericPoison;
84608474 }
84618475
......@@ -9505,8 +9519,8 @@ fn zirFunc(
95059519
95069520 // If this instruction has a body, then it's a function declaration, and we decide
95079521 // the callconv based on whether it is exported. Otherwise, the callconv defaults
9508 // to `.Unspecified`.
9509 const cc: std.builtin.CallingConvention = if (has_body) cc: {
9522 // to `.auto`.
9523 const cc: std.builtin.NewCallingConvention = if (has_body) cc: {
95109524 const func_decl_cau = if (sema.generic_owner != .none) cau: {
95119525 const generic_owner_fn = zcu.funcInfo(sema.generic_owner);
95129526 // The generic owner definitely has a `Cau` for the corresponding function declaration.
......@@ -9518,8 +9532,26 @@ fn zirFunc(
95189532 const zir_decl = sema.code.getDeclaration(decl_inst)[0];
95199533 break :exported zir_decl.flags.is_export;
95209534 };
9521 break :cc if (fn_is_exported) .C else .Unspecified;
9522 } else .Unspecified;
9535 if (fn_is_exported) {
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
95249556 return sema.funcCommon(
95259557 block,
......@@ -9654,15 +9686,64 @@ fn handleExternLibName(
96549686/// These are calling conventions that are confirmed to work with variadic functions.
96559687/// Any calling conventions not included here are either not yet verified to work with variadic
96569688/// functions or there are no more other calling conventions that support variadic functions.
9657const calling_conventions_supporting_var_args = [_]std.builtin.CallingConvention{
9658 .C,
9689const calling_conventions_supporting_var_args = [_]std.builtin.NewCallingConvention.Tag{
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,
96599740};
9660fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention) bool {
9741fn callConvSupportsVarArgs(cc: std.builtin.NewCallingConvention.Tag) bool {
96619742 return for (calling_conventions_supporting_var_args) |supported_cc| {
96629743 if (cc == supported_cc) return true;
96639744 } else false;
96649745}
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 {
96669747 const CallingConventionsSupportingVarArgsList = struct {
96679748 pub fn format(_: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
96689749 _ = fmt;
......@@ -9703,7 +9784,7 @@ fn funcCommon(
97039784 address_space: ?std.builtin.AddressSpace,
97049785 section: Section,
97059786 /// null means generic poison
9706 cc: ?std.builtin.CallingConvention,
9787 cc: ?std.builtin.NewCallingConvention,
97079788 /// this might be Type.generic_poison
97089789 bare_return_type: Type,
97099790 var_args: bool,
......@@ -9743,7 +9824,7 @@ fn funcCommon(
97439824 // default values which are only meaningful for the generic function, *not*
97449825 // the instantiation, which can depend on comptime parameters.
97459826 // Related proposal: https://github.com/ziglang/zig/issues/11834
9746 const cc_resolved = cc orelse .Unspecified;
9827 const cc_resolved = cc orelse .auto;
97479828 var comptime_bits: u32 = 0;
97489829 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {
97499830 const param_ty = Type.fromInterned(param_ty_ip);
......@@ -9761,10 +9842,10 @@ fn funcCommon(
97619842 }
97629843 const this_generic = param_ty.isGenericPoison();
97639844 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)) {
97659846 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});
97669847 }
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)) {
97689849 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)});
97699850 }
97709851 if (!param_ty.isValidParamType(zcu)) {
......@@ -9773,7 +9854,7 @@ fn funcCommon(
97739854 opaque_str, param_ty.fmt(pt),
97749855 });
97759856 }
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)) {
97779858 const msg = msg: {
97789859 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
97799860 param_ty.fmt(pt), @tagName(cc_resolved),
......@@ -9807,15 +9888,24 @@ fn funcCommon(
98079888 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
98089889 }
98099890 switch (cc_resolved) {
9810 .Interrupt => if (target.cpu.arch.isX86()) {
9891 .x86_64_interrupt, .x86_interrupt => {
98119892 const err_code_size = target.ptrBitWidth();
98129893 switch (i) {
98139894 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", .{}),
98149895 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}),
98159896 else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}),
98169897 }
9817 } else return sema.fail(block, param_src, "parameters are not allowed with 'Interrupt' calling convention", .{}),
9818 .Signal => return sema.fail(block, param_src, "parameters are not allowed with 'Signal' calling convention", .{}),
9898 },
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", .{}),
98199909 else => {},
98209910 }
98219911 }
......@@ -10051,7 +10141,7 @@ fn finishFunc(
1005110141 ret_poison: bool,
1005210142 bare_return_type: Type,
1005310143 ret_ty_src: LazySrcLoc,
10054 cc_resolved: std.builtin.CallingConvention,
10144 cc_resolved: std.builtin.NewCallingConvention,
1005510145 is_source_decl: bool,
1005610146 ret_ty_requires_comptime: bool,
1005710147 func_inst: Zir.Inst.Index,
......@@ -10064,7 +10154,6 @@ fn finishFunc(
1006410154 const zcu = pt.zcu;
1006510155 const ip = &zcu.intern_pool;
1006610156 const gpa = sema.gpa;
10067 const target = zcu.getTarget();
1006810157
1006910158 const return_type: Type = if (opt_func_index == .none or ret_poison)
1007010159 bare_return_type
......@@ -10077,7 +10166,7 @@ fn finishFunc(
1007710166 opaque_str, return_type.fmt(pt),
1007810167 });
1007910168 }
10080 if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and
10169 if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and
1008110170 !try sema.validateExternType(return_type, .ret_ty))
1008210171 {
1008310172 const msg = msg: {
......@@ -10134,56 +10223,50 @@ fn finishFunc(
1013410223 }
1013510224
1013610225 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) {
1013810238 return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
1013910239 },
10140 .Inline => if (is_noinline) {
10141 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
10240 .@"inline" => if (is_noinline) {
10241 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'inline'", .{});
1014210242 },
1014310243 else => {},
1014410244 }
1014510245
10146 const arch = target.cpu.arch;
10147 if (@as(?[]const u8, switch (cc_resolved) {
10148 .Unspecified, .C, .Naked, .Async, .Inline => null,
10149 .Interrupt => switch (arch) {
10150 .x86, .x86_64, .avr, .msp430 => null,
10151 else => "x86, x86_64, AVR, and MSP430",
10152 },
10153 .Signal => switch (arch) {
10154 .avr => null,
10155 else => "AVR",
10156 },
10157 .Stdcall, .Fastcall, .Thiscall => switch (arch) {
10158 .x86 => null,
10159 else => "x86",
10160 },
10161 .Vectorcall => switch (arch) {
10162 .x86, .aarch64, .aarch64_be => null,
10163 else => "x86 and AArch64",
10164 },
10165 .APCS, .AAPCS, .AAPCSVFP => switch (arch) {
10166 .arm, .armeb, .aarch64, .aarch64_be, .thumb, .thumbeb => null,
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}", .{
10246 switch (zcu.callconvSupported(cc_resolved)) {
10247 .ok => {},
10248 .bad_arch => |allowed_archs| {
10249 const ArchListFormatter = struct {
10250 archs: []const std.Target.Cpu.Arch,
10251 pub fn format(formatter: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
10252 _ = fmt;
10253 _ = options;
10254 for (formatter.archs, 0..) |arch, i| {
10255 if (i != 0)
10256 try writer.writeAll(", ");
10257 try writer.print("'.{s}'", .{@tagName(arch)});
10258 }
10259 }
10260 };
10261 return sema.fail(block, cc_src, "callconv '{s}' only available on architectures {}", .{
10262 @tagName(cc_resolved),
10263 ArchListFormatter{ .archs = allowed_archs },
10264 });
10265 },
10266 .bad_backend => |bad_backend| return sema.fail(block, cc_src, "callconv '{s}' not supported by compiler backend '{s}'", .{
1018310267 @tagName(cc_resolved),
10184 allowed_platform,
10185 @tagName(arch),
10186 });
10268 @tagName(bad_backend),
10269 }),
1018710270 }
1018810271
1018910272 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
1834218425 } });
1834318426
1834418427 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 = .{
1834718434 // calling_convention: CallingConvention,
18348 (try pt.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
18435 callconv_val.toIntern(),
1834918436 // is_generic: bool,
1835018437 Value.makeBool(func_ty_info.is_generic).toIntern(),
1835118438 // is_var_args: bool,
......@@ -22171,7 +22258,7 @@ fn zirReify(
2217122258 }
2217222259
2217322260 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);
2217522262 if (is_var_args) {
2217622263 try sema.checkCallConvSupportsVarArgs(block, src, cc);
2217722264 }
......@@ -26657,7 +26744,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2665726744 break :blk .{ .explicit = section_name };
2665826745 } 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: {
2666126748 const body_len = sema.code.extra[extra_index];
2666226749 extra_index += 1;
2666326750 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
2667026757 if (val.isGenericPoison()) {
2667126758 break :blk null;
2667226759 }
26673 break :blk zcu.toEnum(std.builtin.CallingConvention, val);
26760 break :blk try sema.analyzeValueAsCallconv(block, cc_src, val);
2667426761 } else if (extra.data.bits.has_cc_ref) blk: {
2667526762 const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
2667626763 extra_index += 1;
......@@ -26689,7 +26776,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2668926776 error.GenericPoison => break :blk null,
2669026777 else => |e| return e,
2669126778 };
26692 break :blk zcu.toEnum(std.builtin.CallingConvention, cc_val);
26779 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
2669326780 } else cc: {
2669426781 if (has_body) {
2669526782 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
2670526792 break :cc .C;
2670626793 }
2670726794 }
26708 break :cc .Unspecified;
26795 break :cc .auto;
2670926796 };
2671026797
2671126798 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
......@@ -27132,9 +27219,15 @@ fn zirInComptime(
2713227219 return if (block.is_comptime) .bool_true else .bool_false;
2713327220}
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 {
2713627223 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));
2713727229 const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
27230
2713827231 const type_name = switch (value) {
2713927232 .atomic_order => "AtomicOrder",
2714027233 .atomic_rmw_op => "AtomicRmwOp",
......@@ -27152,21 +27245,25 @@ fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileErr
2715227245 // Values are handled here.
2715327246 .calling_convention_c => {
2715427247 const callconv_ty = try sema.getBuiltinType("CallingConvention");
27155 comptime assert(@intFromEnum(std.builtin.CallingConvention.C) == 1);
27156 const val = try pt.intern(.{ .enum_tag = .{
27157 .ty = callconv_ty.toIntern(),
27158 .int = .one_u8,
27159 } });
27160 return Air.internedToRef(val);
27248 return try sema.namespaceLookupVal(
27249 block,
27250 src,
27251 callconv_ty.getNamespaceIndex(zcu),
27252 try ip.getOrPutString(gpa, pt.tid, "c", .no_embedded_nulls),
27253 ) orelse @panic("std.builtin is corrupt");
2716127254 },
2716227255 .calling_convention_inline => {
27256 comptime assert(@typeInfo(std.builtin.NewCallingConvention.Tag).@"enum".tag_type == u8);
2716327257 const callconv_ty = try sema.getBuiltinType("CallingConvention");
27164 comptime assert(@intFromEnum(std.builtin.CallingConvention.Inline) == 4);
27165 const val = try pt.intern(.{ .enum_tag = .{
27166 .ty = callconv_ty.toIntern(),
27167 .int = .four_u8,
27168 } });
27169 return Air.internedToRef(val);
27258 const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");
27259 const inline_tag_val = try pt.enumValue(
27260 callconv_tag_ty,
27261 (try pt.intValue(
27262 Type.u8,
27263 @intFromEnum(std.builtin.NewCallingConvention.@"inline"),
27264 )).toIntern(),
27265 );
27266 return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
2717027267 },
2717127268 };
2717227269 const ty = try sema.getBuiltinType(type_name);
......@@ -27353,7 +27450,7 @@ fn explainWhyTypeIsComptimeInner(
2735327450 try sema.errNote(src_loc, msg, "function is generic", .{});
2735427451 }
2735527452 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", .{}),
2735727454 else => {},
2735827455 }
2735927456 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) {
......@@ -27461,13 +27558,12 @@ fn validateExternType(
2746127558 },
2746227559 .@"fn" => {
2746327560 if (position != .other) return false;
27464 const target = zcu.getTarget();
2746527561 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
2746627562 // 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) {
2746827564 return true;
2746927565 }
27470 return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(zcu));
27566 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
2747127567 },
2747227568 .@"enum" => {
2747327569 return sema.validateExternType(ty.intTagType(zcu), position);
......@@ -27547,9 +27643,9 @@ fn explainWhyTypeIsNotExtern(
2754727643 return;
2754827644 }
2754927645 switch (ty.fnCallingConvention(zcu)) {
27550 .Unspecified => 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", .{}),
27552 .Inline => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),
27646 .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
27647 .@"async" => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}),
27648 .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),
2755327649 else => return,
2755427650 }
2755527651 },
......@@ -30525,8 +30621,8 @@ const InMemoryCoercionResult = union(enum) {
3052530621 };
3052630622
3052730623 const CC = struct {
30528 actual: std.builtin.CallingConvention,
30529 wanted: std.builtin.CallingConvention,
30624 actual: std.builtin.NewCallingConvention,
30625 wanted: std.builtin.NewCallingConvention,
3053030626 };
3053130627
3053230628 const BitRange = struct {
......@@ -31176,8 +31272,8 @@ fn coerceInMemoryAllowedFns(
3117631272 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
3117731273 }
3117831274
31179 if (dest_info.cc != src_info.cc) {
31180 return InMemoryCoercionResult{ .fn_cc = .{
31275 if (!callconvCoerceAllowed(target, src_info.cc, dest_info.cc)) {
31276 return .{ .fn_cc = .{
3118131277 .actual = src_info.cc,
3118231278 .wanted = dest_info.cc,
3118331279 } };
......@@ -31250,6 +31346,44 @@ fn coerceInMemoryAllowedFns(
3125031346 return .ok;
3125131347}
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
3125331387fn coerceInMemoryAllowedPtrs(
3125431388 sema: *Sema,
3125531389 block: *Block,
......@@ -36306,7 +36440,7 @@ fn resolveInferredErrorSet(
3630636440 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
3630736441 // so here we can simply skip this case.
3630836442 if (ies_func_info.return_type == .generic_poison_type) {
36309 assert(ies_func_info.cc == .Inline);
36443 assert(ies_func_info.cc == .@"inline");
3631036444 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {
3631136445 if (ies_func_info.is_generic) {
3631236446 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
390390 try writer.writeAll("...");
391391 }
392392 try writer.writeAll(") ");
393 if (fn_info.cc != .Unspecified) {
394 try writer.writeAll("callconv(.");
395 try writer.writeAll(@tagName(fn_info.cc));
396 try writer.writeAll(") ");
393 if (fn_info.cc != .auto) print_cc: {
394 if (zcu.getTarget().defaultCCallingConvention()) |ccc| {
395 if (fn_info.cc.eql(ccc)) {
396 try writer.writeAll("callconv(.c) ");
397 break :print_cc;
398 }
399 }
400 try writer.print("callconv({any}) ", .{fn_info.cc});
397401 }
398402 if (fn_info.return_type == .generic_poison_type) {
399403 try writer.writeAll("anytype");
......@@ -791,7 +795,7 @@ pub fn fnHasRuntimeBitsInner(
791795 const fn_info = zcu.typeToFunc(ty).?;
792796 if (fn_info.is_generic) return false;
793797 if (fn_info.is_var_args) return true;
794 if (fn_info.cc == .Inline) return false;
798 if (fn_info.cc == .@"inline") return false;
795799 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid);
796800}
797801
......@@ -2489,7 +2493,7 @@ pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type {
24892493}
24902494
24912495/// 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 {
24932497 return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.cc;
24942498}
24952499
src/Value.zig+160
......@@ -4490,3 +4490,163 @@ pub fn resolveLazy(
44904490 else => return val,
44914491 }
44924492}
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 {
35393539 zcu.intern_pool.funcSetIesResolved(func_index, .none);
35403540 }
35413541}
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!
20902090 .code = zir,
20912091 .owner = anal_unit,
20922092 .func_index = func_index,
2093 .func_is_naked = fn_ty_info.cc == .Naked,
2093 .func_is_naked = fn_ty_info.cc == .naked,
20942094 .fn_ret_ty = Type.fromInterned(fn_ty_info.return_type),
20952095 .fn_ret_ty_ies = null,
20962096 .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 {
468468 const pt = self.pt;
469469 const zcu = pt.zcu;
470470 const cc = self.fn_type.fnCallingConvention(zcu);
471 if (cc != .Naked) {
471 if (cc != .naked) {
472472 // stp fp, lr, [sp, #-16]!
473473 _ = try self.addInst(.{
474474 .tag = .stp,
......@@ -6229,14 +6229,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62296229 const ret_ty = fn_ty.fnReturnType(zcu);
62306230
62316231 switch (cc) {
6232 .Naked => {
6232 .naked => {
62336233 assert(result.args.len == 0);
62346234 result.return_value = .{ .unreach = {} };
62356235 result.stack_byte_count = 0;
62366236 result.stack_align = 1;
62376237 return result;
62386238 },
6239 .C => {
6239 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => {
62406240 // ARM64 Procedure Call Standard
62416241 var ncrn: usize = 0; // Next Core Register Number
62426242 var nsaa: u32 = 0; // Next stacked argument address
......@@ -6266,7 +6266,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62666266
62676267 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned
62686268 // 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) {
62706270 // Round up NCRN to the next even number
62716271 ncrn += ncrn % 2;
62726272 }
......@@ -6298,7 +6298,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62986298 result.stack_byte_count = nsaa;
62996299 result.stack_align = 16;
63006300 },
6301 .Unspecified => {
6301 .auto => {
63026302 if (ret_ty.zigTypeTag(zcu) == .noreturn) {
63036303 result.return_value = .{ .unreach = {} };
63046304 } 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 {
475475 const pt = self.pt;
476476 const zcu = pt.zcu;
477477 const cc = self.fn_type.fnCallingConvention(zcu);
478 if (cc != .Naked) {
478 if (cc != .naked) {
479479 // push {fp, lr}
480480 const push_reloc = try self.addNop();
481481
......@@ -6196,14 +6196,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
61966196 const ret_ty = fn_ty.fnReturnType(zcu);
61976197
61986198 switch (cc) {
6199 .Naked => {
6199 .naked => {
62006200 assert(result.args.len == 0);
62016201 result.return_value = .{ .unreach = {} };
62026202 result.stack_byte_count = 0;
62036203 result.stack_align = 1;
62046204 return result;
62056205 },
6206 .C => {
6206 .arm_aapcs => {
62076207 // ARM Procedure Call Standard, Chapter 6.5
62086208 var ncrn: usize = 0; // Next Core Register Number
62096209 var nsaa: u32 = 0; // Next stacked argument address
......@@ -6254,7 +6254,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62546254 result.stack_byte_count = nsaa;
62556255 result.stack_align = 8;
62566256 },
6257 .Unspecified => {
6257 .auto => {
62586258 if (ret_ty.zigTypeTag(zcu) == .noreturn) {
62596259 result.return_value = .{ .unreach = {} };
62606260 } 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(
977977 .pt = pt,
978978 .allocator = gpa,
979979 .mir = mir,
980 .cc = .Unspecified,
980 .cc = .auto,
981981 .src_loc = src_loc,
982982 .output_mode = comp.config.output_mode,
983983 .link_mode = comp.config.link_mode,
......@@ -1036,7 +1036,7 @@ fn formatWipMir(
10361036 .instructions = data.func.mir_instructions.slice(),
10371037 .frame_locs = data.func.frame_locs.slice(),
10381038 },
1039 .cc = .Unspecified,
1039 .cc = .auto,
10401040 .src_loc = data.func.src_loc,
10411041 .output_mode = comp.config.output_mode,
10421042 .link_mode = comp.config.link_mode,
......@@ -1238,7 +1238,7 @@ fn gen(func: *Func) !void {
12381238 }
12391239 }
12401240
1241 if (fn_info.cc != .Naked) {
1241 if (fn_info.cc != .naked) {
12421242 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
12431243
12441244 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);
......@@ -4894,7 +4894,7 @@ fn genCall(
48944894 .lib => |lib| try pt.funcType(.{
48954895 .param_types = lib.param_types,
48964896 .return_type = lib.return_type,
4897 .cc = .C,
4897 .cc = func.target.defaultCCallingConvention().?,
48984898 }),
48994899 };
49004900
......@@ -8289,12 +8289,12 @@ fn resolveCallingConventionValues(
82898289 const ret_ty = Type.fromInterned(fn_info.return_type);
82908290
82918291 switch (cc) {
8292 .Naked => {
8292 .naked => {
82938293 assert(result.args.len == 0);
82948294 result.return_value = InstTracking.init(.unreach);
82958295 result.stack_align = .@"8";
82968296 },
8297 .C, .Unspecified => {
8297 .riscv64_lp64, .auto => {
82988298 if (result.args.len > 8) {
82998299 return func.fail("RISC-V calling convention does not support more than 8 arguments", .{});
83008300 }
......@@ -8359,7 +8359,7 @@ fn resolveCallingConventionValues(
83598359
83608360 for (param_types, result.args) |ty, *arg| {
83618361 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
8362 assert(cc == .Unspecified);
8362 assert(cc == .auto);
83638363 arg.* = .none;
83648364 continue;
83658365 }
src/arch/riscv64/Lower.zig+1-1
......@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,
66pic: bool,
77allocator: Allocator,
88mir: Mir,
9cc: std.builtin.CallingConvention,
9cc: std.builtin.NewCallingConvention,
1010err_msg: ?*ErrorMsg = null,
1111src_loc: Zcu.LazySrcLoc,
1212result_insts_len: u8 = undefined,
src/arch/sparc64/CodeGen.zig+3-3
......@@ -366,7 +366,7 @@ fn gen(self: *Self) !void {
366366 const pt = self.pt;
367367 const zcu = pt.zcu;
368368 const cc = self.fn_type.fnCallingConvention(zcu);
369 if (cc != .Naked) {
369 if (cc != .naked) {
370370 // TODO Finish function prologue and epilogue for sparc64.
371371
372372 // save %sp, stack_reserved_area, %sp
......@@ -4441,14 +4441,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)
44414441 const ret_ty = fn_ty.fnReturnType(zcu);
44424442
44434443 switch (cc) {
4444 .Naked => {
4444 .naked => {
44454445 assert(result.args.len == 0);
44464446 result.return_value = .{ .unreach = {} };
44474447 result.stack_byte_count = 0;
44484448 result.stack_align = .@"1";
44494449 return result;
44504450 },
4451 .Unspecified, .C => {
4451 .auto, .sparc64_sysv => {
44524452 // SPARC Compliance Definition 2.4.1, Chapter 3
44534453 // 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 {
11451145/// Memory is owned by the caller.
11461146fn genFunctype(
11471147 gpa: Allocator,
1148 cc: std.builtin.CallingConvention,
1148 cc: std.builtin.NewCallingConvention,
11491149 params: []const InternPool.Index,
11501150 return_type: Type,
11511151 pt: Zcu.PerThread,
......@@ -1160,7 +1160,7 @@ fn genFunctype(
11601160 if (firstParamSRet(cc, return_type, pt, target)) {
11611161 try temp_params.append(.i32); // memory address is always a 32-bit handle
11621162 } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
1163 if (cc == .C) {
1163 if (cc == .wasm_watc) {
11641164 const res_classes = abi.classifyType(return_type, zcu);
11651165 assert(res_classes[0] == .direct and res_classes[1] == .none);
11661166 const scalar_type = abi.scalarType(return_type, zcu);
......@@ -1178,7 +1178,7 @@ fn genFunctype(
11781178 if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11791179
11801180 switch (cc) {
1181 .C => {
1181 .wasm_watc => {
11821182 const param_classes = abi.classifyType(param_type, zcu);
11831183 if (param_classes[1] == .none) {
11841184 if (param_classes[0] == .direct) {
......@@ -1367,7 +1367,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
13671367 .args = &.{},
13681368 .return_value = .none,
13691369 };
1370 if (cc == .Naked) return result;
1370 if (cc == .naked) return result;
13711371
13721372 var args = std.ArrayList(WValue).init(func.gpa);
13731373 defer args.deinit();
......@@ -1382,7 +1382,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
13821382 }
13831383
13841384 switch (cc) {
1385 .Unspecified => {
1385 .auto => {
13861386 for (fn_info.param_types.get(ip)) |ty| {
13871387 if (!Type.fromInterned(ty).hasRuntimeBitsIgnoreComptime(zcu)) {
13881388 continue;
......@@ -1392,7 +1392,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
13921392 func.local_index += 1;
13931393 }
13941394 },
1395 .C => {
1395 .wasm_watc => {
13961396 for (fn_info.param_types.get(ip)) |ty| {
13971397 const ty_classes = abi.classifyType(Type.fromInterned(ty), zcu);
13981398 for (ty_classes) |class| {
......@@ -1408,10 +1408,11 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
14081408 return result;
14091409}
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 {
14121412 switch (cc) {
1413 .Unspecified, .Inline => return isByRef(return_type, pt, target),
1414 .C => {
1413 .@"inline" => unreachable,
1414 .auto => return isByRef(return_type, pt, target),
1415 .wasm_watc => {
14151416 const ty_classes = abi.classifyType(return_type, pt.zcu);
14161417 if (ty_classes[0] == .indirect) return true;
14171418 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.
14231424
14241425/// Lowers a Zig type and its value based on a given calling convention to ensure
14251426/// it matches the ABI.
1426fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {
1427 if (cc != .C) {
1427fn lowerArg(func: *CodeGen, cc: std.builtin.NewCallingConvention, ty: Type, value: WValue) !void {
1428 if (cc != .wasm_watc) {
14281429 return func.lowerToStack(value);
14291430 }
14301431
......@@ -2108,7 +2109,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21082109 // to the stack instead
21092110 if (func.return_value != .none) {
21102111 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)) {
21122113 switch (ret_ty.zigTypeTag(zcu)) {
21132114 // Aggregate types can be lowered as a singular value
21142115 .@"struct", .@"union" => {
......@@ -2286,7 +2287,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
22862287 } else if (first_param_sret) {
22872288 break :result_value sret;
22882289 // 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") {
22902291 const result_local = try func.allocLocal(ret_ty);
22912292 try func.addLabel(.local_set, result_local.local.value);
22922293 const scalar_type = abi.scalarType(ret_ty, zcu);
......@@ -2565,7 +2566,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
25652566 const arg = func.args[arg_index];
25662567 const cc = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?.cc;
25672568 const arg_ty = func.typeOfIndex(inst);
2568 if (cc == .C) {
2569 if (cc == .wasm_watc) {
25692570 const arg_classes = abi.classifyType(arg_ty, zcu);
25702571 for (arg_classes) |class| {
25712572 if (class != .none) {
......@@ -7175,12 +7176,12 @@ fn callIntrinsic(
71757176 // Always pass over C-ABI
71767177 const pt = func.pt;
71777178 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.*);
71797180 defer func_type.deinit(func.gpa);
71807181 const func_type_index = try func.bin_file.zigObjectPtr().?.putOrGetFuncType(func.gpa, func_type);
71817182 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.*);
71847185 // if we want return as first param, we allocate a pointer to stack,
71857186 // and emit it as our first argument
71867187 const sret = if (want_sret_param) blk: {
......@@ -7193,7 +7194,7 @@ fn callIntrinsic(
71937194 for (args, 0..) |arg, arg_i| {
71947195 assert(!(want_sret_param and arg == .stack));
71957196 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);
71977198 }
71987199
71997200 // Actually call our intrinsic
src/arch/x86_64/CodeGen.zig+32-33
......@@ -918,13 +918,13 @@ pub fn generate(
918918 );
919919 function.va_info = switch (cc) {
920920 else => undefined,
921 .SysV => .{ .sysv = .{
921 .x86_64_sysv => .{ .sysv = .{
922922 .gp_count = call_info.gp_count,
923923 .fp_count = call_info.fp_count,
924924 .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count },
925925 .reg_save_area = undefined,
926926 } },
927 .Win64 => .{ .win64 = .{} },
927 .x86_64_win => .{ .win64 = .{} },
928928 };
929929
930930 function.gen() catch |err| switch (err) {
......@@ -1053,7 +1053,7 @@ pub fn generateLazy(
10531053 .bin_file = bin_file,
10541054 .allocator = gpa,
10551055 .mir = mir,
1056 .cc = abi.resolveCallingConvention(.Unspecified, function.target.*),
1056 .cc = abi.resolveCallingConvention(.auto, function.target.*),
10571057 .src_loc = src_loc,
10581058 .output_mode = comp.config.output_mode,
10591059 .link_mode = comp.config.link_mode,
......@@ -1159,7 +1159,7 @@ fn formatWipMir(
11591159 .extra = data.self.mir_extra.items,
11601160 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
11611161 },
1162 .cc = .Unspecified,
1162 .cc = .auto,
11631163 .src_loc = data.self.src_loc,
11641164 .output_mode = comp.config.output_mode,
11651165 .link_mode = comp.config.link_mode,
......@@ -2023,7 +2023,7 @@ fn gen(self: *Self) InnerError!void {
20232023 const zcu = pt.zcu;
20242024 const fn_info = zcu.typeToFunc(self.fn_type).?;
20252025 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
2026 if (cc != .Naked) {
2026 if (cc != .naked) {
20272027 try self.asmRegister(.{ ._, .push }, .rbp);
20282028 try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));
20292029 try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));
......@@ -2056,7 +2056,7 @@ fn gen(self: *Self) InnerError!void {
20562056 }
20572057
20582058 if (fn_info.is_var_args) switch (cc) {
2059 .SysV => {
2059 .x86_64_sysv => {
20602060 const info = &self.va_info.sysv;
20612061 const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{
20622062 .size = abi.SysV.c_abi_int_param_regs.len * 8 +
......@@ -2089,7 +2089,7 @@ fn gen(self: *Self) InnerError!void {
20892089
20902090 self.performReloc(skip_sse_reloc);
20912091 },
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", .{}),
20932093 else => unreachable,
20942094 };
20952095
......@@ -2541,7 +2541,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
25412541 const enum_ty = Type.fromInterned(lazy_sym.ty);
25422542 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.*);
25452545 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
25462546 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
25472547 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);
......@@ -2694,7 +2694,7 @@ fn setFrameLoc(
26942694 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
26952695}
26962696
2697fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout {
2697fn computeFrameLayout(self: *Self, cc: std.builtin.NewCallingConvention) !FrameLayout {
26982698 const frame_allocs_len = self.frame_allocs.len;
26992699 try self.frame_locs.resize(self.gpa, frame_allocs_len);
27002700 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 {
30063006 }
30073007}
30083008
3009pub fn spillCallerPreservedRegs(self: *Self, cc: std.builtin.CallingConvention) !void {
3009pub fn spillCallerPreservedRegs(self: *Self, cc: std.builtin.NewCallingConvention) !void {
30103010 switch (cc) {
3011 inline .SysV, .Win64 => |known_cc| try self.spillRegisters(
3012 comptime abi.getCallerPreservedRegs(known_cc),
3013 ),
3011 .x86_64_sysv => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_sysv = .{} })),
3012 .x86_64_win => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_win = .{} })),
30143013 else => unreachable,
30153014 }
30163015}
......@@ -12384,7 +12383,7 @@ fn genCall(self: *Self, info: union(enum) {
1238412383 .lib => |lib| try pt.funcType(.{
1238512384 .param_types = lib.param_types,
1238612385 .return_type = lib.return_type,
12387 .cc = .C,
12386 .cc = self.target.defaultCCallingConvention().?,
1238812387 }),
1238912388 };
1239012389 const fn_info = zcu.typeToFunc(fn_ty).?;
......@@ -12543,7 +12542,7 @@ fn genCall(self: *Self, info: union(enum) {
1254312542 src_arg,
1254412543 .{},
1254512544 ),
12546 .C, .SysV, .Win64 => {
12545 .x86_64_sysv, .x86_64_win => {
1254712546 const promoted_ty = self.promoteInt(arg_ty);
1254812547 const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu));
1254912548 const dst_alias = registerAlias(dst_reg, promoted_abi_size);
......@@ -16822,7 +16821,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
1682216821 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
1682316822 const inst_ty = self.typeOfIndex(inst);
1682416823 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
1682716826 // We need a properly aligned and sized call frame to be able to call this function.
1682816827 {
......@@ -18915,7 +18914,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {
1891518914 self.fn_type.fnCallingConvention(zcu),
1891618915 self.target.*,
1891718916 )) {
18918 .SysV => result: {
18917 .x86_64_sysv => result: {
1891918918 const info = self.va_info.sysv;
1892018919 const dst_fi = try self.allocFrameIndex(FrameAlloc.initSpill(va_list_ty, zcu));
1892118920 var field_off: u31 = 0;
......@@ -18957,7 +18956,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {
1895718956 field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu));
1895818957 break :result .{ .load_frame = .{ .index = dst_fi } };
1895918958 },
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", .{}),
1896118960 else => unreachable,
1896218961 };
1896318962 return self.finishAir(inst, result, .{ .none, .none, .none });
......@@ -18976,7 +18975,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
1897618975 self.fn_type.fnCallingConvention(zcu),
1897718976 self.target.*,
1897818977 )) {
18979 .SysV => result: {
18978 .x86_64_sysv => result: {
1898018979 try self.spillEflagsIfOccupied();
1898118980
1898218981 const tmp_regs =
......@@ -19155,7 +19154,7 @@ fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
1915519154 );
1915619155 break :result promote_mcv;
1915719156 },
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", .{}),
1915919158 else => unreachable,
1916019159 };
1916119160 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -19324,12 +19323,12 @@ fn resolveCallingConventionValues(
1932419323
1932519324 const resolved_cc = abi.resolveCallingConvention(cc, self.target.*);
1932619325 switch (cc) {
19327 .Naked => {
19326 .naked => {
1932819327 assert(result.args.len == 0);
1932919328 result.return_value = InstTracking.init(.unreach);
1933019329 result.stack_align = .@"8";
1933119330 },
19332 .C, .SysV, .Win64 => {
19331 .x86_64_sysv, .x86_64_win => {
1933319332 var ret_int_reg_i: u32 = 0;
1933419333 var ret_sse_reg_i: u32 = 0;
1933519334 var param_int_reg_i: u32 = 0;
......@@ -19337,8 +19336,8 @@ fn resolveCallingConventionValues(
1933719336 result.stack_align = .@"16";
1933819337
1933919338 switch (resolved_cc) {
19340 .SysV => {},
19341 .Win64 => {
19339 .x86_64_sysv => {},
19340 .x86_64_win => {
1934219341 // Align the stack to 16bytes before allocating shadow stack space (if any).
1934319342 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(zcu));
1934419343 },
......@@ -19356,8 +19355,8 @@ fn resolveCallingConventionValues(
1935619355 var ret_tracking_i: usize = 0;
1935719356
1935819357 const classes = switch (resolved_cc) {
19359 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none),
19360 .Win64 => &.{abi.classifyWindows(ret_ty, zcu)},
19358 .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none),
19359 .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)},
1936119360 else => unreachable,
1936219361 };
1936319362 for (classes) |class| switch (class) {
......@@ -19419,8 +19418,8 @@ fn resolveCallingConventionValues(
1941919418 for (param_types, result.args) |ty, *arg| {
1942019419 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1942119420 switch (resolved_cc) {
19422 .SysV => {},
19423 .Win64 => {
19421 .x86_64_sysv => {},
19422 .x86_64_win => {
1942419423 param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i);
1942519424 param_sse_reg_i = param_int_reg_i;
1942619425 },
......@@ -19431,8 +19430,8 @@ fn resolveCallingConventionValues(
1943119430 var arg_mcv_i: usize = 0;
1943219431
1943319432 const classes = switch (resolved_cc) {
19434 .SysV => mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none),
19435 .Win64 => &.{abi.classifyWindows(ty, zcu)},
19433 .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none),
19434 .x86_64_win => &.{abi.classifyWindows(ty, zcu)},
1943619435 else => unreachable,
1943719436 };
1943819437 for (classes) |class| switch (class) {
......@@ -19464,11 +19463,11 @@ fn resolveCallingConventionValues(
1946419463 },
1946519464 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
1946619465 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {
19467 .SysV => switch (class) {
19466 .x86_64_sysv => switch (class) {
1946819467 .x87, .x87up, .complex_x87, .memory => break,
1946919468 else => unreachable,
1947019469 },
19471 .Win64 => if (ty.abiSize(zcu) > 8) {
19470 .x86_64_win => if (ty.abiSize(zcu) > 8) {
1947219471 const param_int_reg =
1947319472 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64();
1947419473 param_int_reg_i += 1;
......@@ -19530,7 +19529,7 @@ fn resolveCallingConventionValues(
1953019529 assert(param_sse_reg_i <= 16);
1953119530 result.fp_count = param_sse_reg_i;
1953219531 },
19533 .Unspecified => {
19532 .auto => {
1953419533 result.stack_align = .@"16";
1953519534
1953619535 // Return values
src/arch/x86_64/Lower.zig+1-1
......@@ -6,7 +6,7 @@ link_mode: std.builtin.LinkMode,
66pic: bool,
77allocator: std.mem.Allocator,
88mir: Mir,
9cc: std.builtin.CallingConvention,
9cc: std.builtin.NewCallingConvention,
1010err_msg: ?*Zcu.ErrorMsg = null,
1111src_loc: Zcu.LazySrcLoc,
1212result_insts_len: u8 = undefined,
src/arch/x86_64/abi.zig+23-23
......@@ -436,62 +436,62 @@ pub const Win64 = struct {
436436};
437437
438438pub fn resolveCallingConvention(
439 cc: std.builtin.CallingConvention,
439 cc: std.builtin.NewCallingConvention,
440440 target: std.Target,
441) std.builtin.CallingConvention {
441) std.builtin.NewCallingConvention {
442442 return switch (cc) {
443 .Unspecified, .C => switch (target.os.tag) {
444 else => .SysV,
445 .windows => .Win64,
443 .auto => switch (target.os.tag) {
444 else => .{ .x86_64_sysv = .{} },
445 .windows => .{ .x86_64_win = .{} },
446446 },
447447 else => cc,
448448 };
449449}
450450
451pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention) []const Register {
451pub fn getCalleePreservedRegs(cc: std.builtin.NewCallingConvention) []const Register {
452452 return switch (cc) {
453 .SysV => &SysV.callee_preserved_regs,
454 .Win64 => &Win64.callee_preserved_regs,
453 .x86_64_sysv => &SysV.callee_preserved_regs,
454 .x86_64_win => &Win64.callee_preserved_regs,
455455 else => unreachable,
456456 };
457457}
458458
459pub fn getCallerPreservedRegs(cc: std.builtin.CallingConvention) []const Register {
459pub fn getCallerPreservedRegs(cc: std.builtin.NewCallingConvention) []const Register {
460460 return switch (cc) {
461 .SysV => &SysV.caller_preserved_regs,
462 .Win64 => &Win64.caller_preserved_regs,
461 .x86_64_sysv => &SysV.caller_preserved_regs,
462 .x86_64_win => &Win64.caller_preserved_regs,
463463 else => unreachable,
464464 };
465465}
466466
467pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention) []const Register {
467pub fn getCAbiIntParamRegs(cc: std.builtin.NewCallingConvention) []const Register {
468468 return switch (cc) {
469 .SysV => &SysV.c_abi_int_param_regs,
470 .Win64 => &Win64.c_abi_int_param_regs,
469 .x86_64_sysv => &SysV.c_abi_int_param_regs,
470 .x86_64_win => &Win64.c_abi_int_param_regs,
471471 else => unreachable,
472472 };
473473}
474474
475pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention) []const Register {
475pub fn getCAbiSseParamRegs(cc: std.builtin.NewCallingConvention) []const Register {
476476 return switch (cc) {
477 .SysV => &SysV.c_abi_sse_param_regs,
478 .Win64 => &Win64.c_abi_sse_param_regs,
477 .x86_64_sysv => &SysV.c_abi_sse_param_regs,
478 .x86_64_win => &Win64.c_abi_sse_param_regs,
479479 else => unreachable,
480480 };
481481}
482482
483pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention) []const Register {
483pub fn getCAbiIntReturnRegs(cc: std.builtin.NewCallingConvention) []const Register {
484484 return switch (cc) {
485 .SysV => &SysV.c_abi_int_return_regs,
486 .Win64 => &Win64.c_abi_int_return_regs,
485 .x86_64_sysv => &SysV.c_abi_int_return_regs,
486 .x86_64_win => &Win64.c_abi_int_return_regs,
487487 else => unreachable,
488488 };
489489}
490490
491pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register {
491pub fn getCAbiSseReturnRegs(cc: std.builtin.NewCallingConvention) []const Register {
492492 return switch (cc) {
493 .SysV => &SysV.c_abi_sse_return_regs,
494 .Win64 => &Win64.c_abi_sse_return_regs,
493 .x86_64_sysv => &SysV.c_abi_sse_return_regs,
494 .x86_64_win => &Win64.c_abi_sse_return_regs,
495495 else => unreachable,
496496 };
497497}
src/codegen/c.zig+13-8
......@@ -1783,7 +1783,7 @@ pub const DeclGen = struct {
17831783 const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
17841784
17851785 const fn_info = zcu.typeToFunc(fn_ty).?;
1786 if (fn_info.cc == .Naked) {
1786 if (fn_info.cc == .naked) {
17871787 switch (kind) {
17881788 .forward => try w.writeAll("zig_naked_decl "),
17891789 .complete => try w.writeAll("zig_naked "),
......@@ -1796,7 +1796,7 @@ pub const DeclGen = struct {
17961796
17971797 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| {
18001800 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
18011801 trailing = .maybe_space;
18021802 }
......@@ -7604,12 +7604,17 @@ fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void {
76047604 return w.writeAll(toMemoryOrder(order));
76057605}
76067606
7607fn toCallingConvention(call_conv: std.builtin.CallingConvention) ?[]const u8 {
7608 return switch (call_conv) {
7609 .Stdcall => "stdcall",
7610 .Fastcall => "fastcall",
7611 .Vectorcall => "vectorcall",
7612 else => null,
7607fn toCallingConvention(cc: std.builtin.NewCallingConvention, zcu: *Zcu) ?[]const u8 {
7608 return switch (cc) {
7609 .auto, .naked => null,
7610 .x86_stdcall => "stdcall",
7611 .x86_fastcall => "fastcall",
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 },
76137618 };
76147619}
76157620
src/codegen/llvm.zig+351-243
......@@ -1159,7 +1159,7 @@ pub const Object = struct {
11591159 }
11601160
11611161 {
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);
11631163 defer module_flags.deinit();
11641164
11651165 const behavior_error = try o.builder.metadataConstant(try o.builder.intConst(.i32, 1));
......@@ -1233,6 +1233,18 @@ pub const Object = struct {
12331233 }
12341234 }
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
12361248 try o.builder.metadataNamed(try o.builder.metadataString("llvm.module.flags"), module_flags.items);
12371249 }
12381250
......@@ -1467,14 +1479,6 @@ pub const Object = struct {
14671479 _ = try attributes.removeFnAttr(.@"noinline");
14681480 }
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
14781482 if (func_analysis.branch_hint == .cold) {
14791483 try attributes.addFnAttr(.cold, &o.builder);
14801484 } else {
......@@ -1486,7 +1490,7 @@ pub const Object = struct {
14861490 } else {
14871491 _ = try attributes.removeFnAttr(.sanitize_thread);
14881492 }
1489 const is_naked = fn_info.cc == .Naked;
1493 const is_naked = fn_info.cc == .naked;
14901494 if (owner_mod.fuzz and !func_analysis.disable_instrumentation and !is_naked) {
14911495 try attributes.addFnAttr(.optforfuzzing, &o.builder);
14921496 _ = try attributes.removeFnAttr(.skipprofile);
......@@ -1784,7 +1788,7 @@ pub const Object = struct {
17841788 .liveness = liveness,
17851789 .ng = &ng,
17861790 .wip = wip,
1787 .is_naked = fn_info.cc == .Naked,
1791 .is_naked = fn_info.cc == .naked,
17881792 .fuzz = fuzz,
17891793 .ret_ptr = ret_ptr,
17901794 .args = args.items,
......@@ -3038,14 +3042,33 @@ pub const Object = struct {
30383042 llvm_arg_i += 1;
30393043 }
30403044
3041 switch (fn_info.cc) {
3042 .Unspecified, .Inline => function_index.setCallConv(.fastcc, &o.builder),
3043 .Naked => try attributes.addFnAttr(.naked, &o.builder),
3044 .Async => {
3045 function_index.setCallConv(.fastcc, &o.builder);
3046 @panic("TODO: LLVM backend lower async function");
3047 },
3048 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
3045 if (fn_info.cc == .@"async") {
3046 @panic("TODO: LLVM backend lower async function");
3047 }
3048
3049 {
3050 const cc_info = toLlvmCallConv(fn_info.cc, target).?;
3051
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 }
30493072 }
30503073
30513074 if (resolved.alignment != .none)
......@@ -3061,7 +3084,7 @@ pub const Object = struct {
30613084 // suppress generation of the prologue and epilogue, and the prologue is where the
30623085 // frame pointer normally gets set up. At time of writing, this is the case for at
30633086 // 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,
30653088 );
30663089
30673090 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
......@@ -4618,9 +4641,16 @@ pub const Object = struct {
46184641 if (!param_ty.isPtrLikeOptional(zcu) and !ptr_info.flags.is_allowzero) {
46194642 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
46204643 }
4621 if (fn_info.cc == .Interrupt) {
4622 const child_type = try lowerType(o, Type.fromInterned(ptr_info.child));
4623 try attributes.addParamAttr(llvm_arg_i, .{ .byval = child_type }, &o.builder);
4644 switch (fn_info.cc) {
4645 else => {},
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 },
46244654 }
46254655 if (ptr_info.flags.is_const) {
46264656 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
......@@ -5677,7 +5707,7 @@ pub const FuncGen = struct {
56775707 .always_tail => .musttail,
56785708 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
56795709 },
5680 toLlvmCallConv(fn_info.cc, target),
5710 toLlvmCallConvTag(fn_info.cc, target).?,
56815711 try attributes.finish(&o.builder),
56825712 try o.lowerType(zig_fn_ty),
56835713 llvm_fn,
......@@ -5756,7 +5786,7 @@ pub const FuncGen = struct {
57565786 _ = try fg.wip.callIntrinsicAssumeCold();
57575787 _ = try fg.wip.call(
57585788 .normal,
5759 toLlvmCallConv(fn_info.cc, target),
5789 toLlvmCallConvTag(fn_info.cc, target).?,
57605790 .none,
57615791 panic_global.typeOf(&o.builder),
57625792 panic_global.toValue(&o.builder),
......@@ -11554,36 +11584,146 @@ fn toLlvmAtomicRmwBinOp(
1155411584 };
1155511585}
1155611586
11557fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
11558 return switch (cc) {
11559 .Unspecified, .Inline, .Async => .fastcc,
11560 .C, .Naked => .ccc,
11561 .Stdcall => .x86_stdcallcc,
11562 .Fastcall => .x86_fastcallcc,
11563 .Vectorcall => return switch (target.cpu.arch) {
11564 .x86, .x86_64 => .x86_vectorcallcc,
11565 .aarch64, .aarch64_be => .aarch64_vector_pcs,
11566 else => unreachable,
11567 },
11568 .Thiscall => .x86_thiscallcc,
11569 .APCS => .arm_apcscc,
11570 .AAPCS => .arm_aapcscc,
11571 .AAPCSVFP => .arm_aapcs_vfpcc,
11572 .Interrupt => return switch (target.cpu.arch) {
11573 .x86, .x86_64 => .x86_intrcc,
11574 .avr => .avr_intrcc,
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,
11587const CallingConventionInfo = struct {
11588 /// The LLVM calling convention to use.
11589 llvm_cc: Builder.CallConv,
11590 /// Whether to use an `alignstack` attribute to forcibly re-align the stack pointer in the function's prologue.
11591 align_stack: bool,
11592 /// Whether the function needs a `naked` attribute.
11593 naked: bool,
11594 /// How many leading parameters to apply the `inreg` attribute to.
11595 inreg_param_count: u2 = 0,
11596};
11597
11598pub fn toLlvmCallConv(cc: std.builtin.NewCallingConvention, target: std.Target) ?CallingConventionInfo {
11599 const llvm_cc = toLlvmCallConvTag(cc, target) orelse return null;
11600 const incoming_stack_alignment: ?u64, const register_params: u2 = switch (cc) {
11601 inline else => |pl| switch (@TypeOf(pl)) {
11602 void => .{ null, 0 },
11603 std.builtin.NewCallingConvention.CommonOptions => .{ pl.incoming_stack_alignment, 0 },
11604 std.builtin.NewCallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params },
1158411605 else => unreachable,
1158511606 },
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,
1158711727 };
1158811728}
1158911729
......@@ -11711,31 +11851,27 @@ fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Targe
1171111851 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
1171211852
1171311853 return switch (fn_info.cc) {
11714 .Unspecified, .Inline => returnTypeByRef(zcu, target, return_type),
11715 .C => switch (target.cpu.arch) {
11716 .mips, .mipsel => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11717 .memory, .i32_array => true,
11718 .byval => false,
11719 },
11720 .x86 => isByRef(return_type, zcu),
11721 .x86_64 => switch (target.os.tag) {
11722 .windows => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
11723 else => firstParamSRetSystemV(return_type, zcu, target),
11724 },
11725 .wasm32 => wasm_c_abi.classifyType(return_type, zcu)[0] == .indirect,
11726 .aarch64, .aarch64_be => aarch64_c_abi.classifyType(return_type, zcu) == .memory,
11727 .arm, .armeb => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
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
11854 .auto => returnTypeByRef(zcu, target, return_type),
11855 .x86_64_sysv => firstParamSRetSystemV(return_type, zcu, target),
11856 .x86_64_win => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
11857 .x86_sysv, .x86_win => isByRef(return_type, zcu),
11858 .x86_stdcall => !isScalar(zcu, return_type),
11859 .wasm_watc => wasm_c_abi.classifyType(return_type, zcu)[0] == .indirect,
11860 .aarch64_aapcs,
11861 .aarch64_aapcs_darwin,
11862 .aarch64_aapcs_win,
11863 => aarch64_c_abi.classifyType(return_type, zcu) == .memory,
11864 .arm_aapcs => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
11865 .memory, .i64_array => true,
11866 .i32_array => |size| size != 1,
11867 .byval => false,
1173411868 },
11735 .SysV => firstParamSRetSystemV(return_type, zcu, target),
11736 .Win64 => x86_64_abi.classifyWindows(return_type, zcu) == .memory,
11737 .Stdcall => !isScalar(zcu, return_type),
11738 else => false,
11869 .riscv64_lp64, .riscv32_ilp32 => riscv_c_abi.classifyType(return_type, zcu) == .memory,
11870 .mips64_n64, .mips64_n32, .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11871 .memory, .i32_array => true,
11872 .byval => false,
11873 },
11874 else => false, // TODO: investigate other targets/callconvs
1173911875 };
1174011876}
1174111877
......@@ -11761,82 +11897,64 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
1176111897 }
1176211898 const target = zcu.getTarget();
1176311899 switch (fn_info.cc) {
11764 .Unspecified,
11765 .Inline,
11766 => return if (returnTypeByRef(zcu, target, return_type)) .void else o.lowerType(return_type),
11767
11768 .C => {
11769 switch (target.cpu.arch) {
11770 .mips, .mipsel => {
11771 switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11772 .memory, .i32_array => return .void,
11773 .byval => return o.lowerType(return_type),
11774 }
11775 },
11776 .x86 => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type),
11777 .x86_64 => switch (target.os.tag) {
11778 .windows => return lowerWin64FnRetTy(o, fn_info),
11779 else => return lowerSystemVFnRetTy(o, fn_info),
11780 },
11781 .wasm32 => {
11782 if (isScalar(zcu, return_type)) {
11783 return o.lowerType(return_type);
11784 }
11785 const classes = wasm_c_abi.classifyType(return_type, zcu);
11786 if (classes[0] == .indirect or classes[0] == .none) {
11787 return .void;
11788 }
11789
11790 assert(classes[0] == .direct and classes[1] == .none);
11791 const scalar_type = wasm_c_abi.scalarType(return_type, zcu);
11792 return o.builder.intType(@intCast(scalar_type.abiSize(zcu) * 8));
11793 },
11794 .aarch64, .aarch64_be => {
11795 switch (aarch64_c_abi.classifyType(return_type, zcu)) {
11796 .memory => return .void,
11797 .float_array => return o.lowerType(return_type),
11798 .byval => return o.lowerType(return_type),
11799 .integer => return o.builder.intType(@intCast(return_type.bitSize(zcu))),
11800 .double_integer => return o.builder.arrayType(2, .i64),
11801 }
11802 },
11803 .arm, .armeb => {
11804 switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
11805 .memory, .i64_array => return .void,
11806 .i32_array => |len| return if (len == 1) .i32 else .void,
11807 .byval => return o.lowerType(return_type),
11808 }
11809 },
11810 .riscv32, .riscv64 => {
11811 switch (riscv_c_abi.classifyType(return_type, zcu)) {
11812 .memory => return .void,
11813 .integer => {
11814 return o.builder.intType(@intCast(return_type.bitSize(zcu)));
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),
11900 .@"inline" => unreachable,
11901 .auto => return if (returnTypeByRef(zcu, target, return_type)) .void else o.lowerType(return_type),
11902
11903 .x86_64_sysv => return lowerSystemVFnRetTy(o, fn_info),
11904 .x86_64_win => return lowerWin64FnRetTy(o, fn_info),
11905 .x86_stdcall => return if (isScalar(zcu, return_type)) o.lowerType(return_type) else .void,
11906 .x86_sysv, .x86_win => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type),
11907 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(return_type, zcu)) {
11908 .memory => return .void,
11909 .float_array => return o.lowerType(return_type),
11910 .byval => return o.lowerType(return_type),
11911 .integer => return o.builder.intType(@intCast(return_type.bitSize(zcu))),
11912 .double_integer => return o.builder.arrayType(2, .i64),
11913 },
11914 .arm_aapcs => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) {
11915 .memory, .i64_array => return .void,
11916 .i32_array => |len| return if (len == 1) .i32 else .void,
11917 .byval => return o.lowerType(return_type),
11918 },
11919 .mips64_n64, .mips64_n32, .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) {
11920 .memory, .i32_array => return .void,
11921 .byval => return o.lowerType(return_type),
11922 },
11923 .riscv64_lp64, .riscv32_ilp32 => switch (riscv_c_abi.classifyType(return_type, zcu)) {
11924 .memory => return .void,
11925 .integer => {
11926 return o.builder.intType(@intCast(return_type.bitSize(zcu)));
11927 },
11928 .double_integer => {
11929 return o.builder.structType(.normal, &.{ .i64, .i64 });
11930 },
11931 .byval => return o.lowerType(return_type),
11932 .fields => {
11933 var types_len: usize = 0;
11934 var types: [8]Builder.Type = undefined;
11935 for (0..return_type.structFieldCount(zcu)) |field_index| {
11936 const field_ty = return_type.fieldType(field_index, zcu);
11937 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
11938 types[types_len] = try o.lowerType(field_ty);
11939 types_len += 1;
11940 }
11941 return o.builder.structType(.normal, types[0..types_len]);
11942 },
11943 },
11944 .wasm_watc => {
11945 if (isScalar(zcu, return_type)) {
11946 return o.lowerType(return_type);
11947 }
11948 const classes = wasm_c_abi.classifyType(return_type, zcu);
11949 if (classes[0] == .indirect or classes[0] == .none) {
11950 return .void;
1183511951 }
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));
1183611956 },
11837 .Win64 => return lowerWin64FnRetTy(o, fn_info),
11838 .SysV => return lowerSystemVFnRetTy(o, fn_info),
11839 .Stdcall => return if (isScalar(zcu, return_type)) o.lowerType(return_type) else .void,
11957 // TODO investigate other callconvs
1184011958 else => return o.lowerType(return_type),
1184111959 }
1184211960}
......@@ -11989,7 +12107,8 @@ const ParamTypeIterator = struct {
1198912107 return .no_bits;
1199012108 }
1199112109 switch (it.fn_info.cc) {
11992 .Unspecified, .Inline => {
12110 .@"inline" => unreachable,
12111 .auto => {
1199312112 it.zig_index += 1;
1199412113 it.llvm_index += 1;
1199512114 if (ty.isSlice(zcu) or
......@@ -12010,97 +12129,12 @@ const ParamTypeIterator = struct {
1201012129 return .byval;
1201112130 }
1201212131 },
12013 .Async => {
12132 .@"async" => {
1201412133 @panic("TODO implement async function lowering in the LLVM backend");
1201512134 },
12016 .C => switch (target.cpu.arch) {
12017 .mips, .mipsel => {
12018 it.zig_index += 1;
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 => {
12135 .x86_64_sysv => return it.nextSystemV(ty),
12136 .x86_64_win => return it.nextWin64(ty),
12137 .x86_stdcall => {
1210412138 it.zig_index += 1;
1210512139 it.llvm_index += 1;
1210612140
......@@ -12111,6 +12145,80 @@ const ParamTypeIterator = struct {
1211112145 return .byref;
1211212146 }
1211312147 },
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
1211412222 else => {
1211512223 it.zig_index += 1;
1211612224 it.llvm_index += 1;
......@@ -12263,13 +12371,13 @@ fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTyp
1226312371}
1226412372
1226512373fn ccAbiPromoteInt(
12266 cc: std.builtin.CallingConvention,
12374 cc: std.builtin.NewCallingConvention,
1226712375 zcu: *Zcu,
1226812376 ty: Type,
1226912377) ?std.builtin.Signedness {
1227012378 const target = zcu.getTarget();
1227112379 switch (cc) {
12272 .Unspecified, .Inline, .Async => return null,
12380 .auto, .@"inline", .@"async" => return null,
1227312381 else => {},
1227412382 }
1227512383 const int_info = switch (ty.zigTypeTag(zcu)) {
src/codegen/llvm/Builder.zig+13
......@@ -2052,6 +2052,7 @@ pub const CallConv = enum(u10) {
20522052 x86_intrcc,
20532053 avr_intrcc,
20542054 avr_signalcc,
2055 avr_builtincc,
20552056
20562057 amdgpu_vs = 87,
20572058 amdgpu_gs,
......@@ -2060,6 +2061,7 @@ pub const CallConv = enum(u10) {
20602061 amdgpu_kernel,
20612062 x86_regcallcc,
20622063 amdgpu_hs,
2064 msp430_builtincc,
20632065
20642066 amdgpu_ls = 95,
20652067 amdgpu_es,
......@@ -2068,9 +2070,15 @@ pub const CallConv = enum(u10) {
20682070
20692071 amdgpu_gfx = 100,
20702072
2073 m68k_intrcc,
2074
20712075 aarch64_sme_preservemost_from_x0 = 102,
20722076 aarch64_sme_preservemost_from_x2,
20732077
2078 m68k_rtdcc = 106,
2079
2080 riscv_vectorcallcc = 110,
2081
20742082 _,
20752083
20762084 pub const default = CallConv.ccc;
......@@ -2115,6 +2123,7 @@ pub const CallConv = enum(u10) {
21152123 .x86_intrcc,
21162124 .avr_intrcc,
21172125 .avr_signalcc,
2126 .avr_builtincc,
21182127 .amdgpu_vs,
21192128 .amdgpu_gs,
21202129 .amdgpu_ps,
......@@ -2122,13 +2131,17 @@ pub const CallConv = enum(u10) {
21222131 .amdgpu_kernel,
21232132 .x86_regcallcc,
21242133 .amdgpu_hs,
2134 .msp430_builtincc,
21252135 .amdgpu_ls,
21262136 .amdgpu_es,
21272137 .aarch64_vector_pcs,
21282138 .aarch64_sve_vector_pcs,
21292139 .amdgpu_gfx,
2140 .m68k_intrcc,
21302141 .aarch64_sme_preservemost_from_x0,
21312142 .aarch64_sme_preservemost_from_x2,
2143 .m68k_rtdcc,
2144 .riscv_vectorcallcc,
21322145 => try writer.print(" {s}", .{@tagName(self)}),
21332146 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
21342147 }
src/codegen/spirv.zig+3-3
......@@ -1640,8 +1640,8 @@ const NavGen = struct {
16401640
16411641 comptime assert(zig_call_abi_ver == 3);
16421642 switch (fn_info.cc) {
1643 .Unspecified, .Kernel, .Fragment, .Vertex, .C => {},
1644 else => unreachable, // TODO
1643 .auto, .spirv_kernel, .spirv_fragment, .spirv_vertex => {},
1644 else => @panic("TODO"),
16451645 }
16461646
16471647 // TODO: Put this somewhere in Sema.zig
......@@ -2970,7 +2970,7 @@ const NavGen = struct {
29702970 .id_result_type = return_ty_id,
29712971 .id_result = result_id,
29722972 .function_control = switch (fn_info.cc) {
2973 .Inline => .{ .Inline = true },
2973 .@"inline" => .{ .Inline = true },
29742974 else => .{},
29752975 },
29762976 .function_type = prototype_ty_id,
src/link/C.zig+1-1
......@@ -217,7 +217,7 @@ pub fn updateFunc(
217217 .mod = zcu.navFileScope(func.owner_nav).mod,
218218 .error_msg = null,
219219 .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,
221221 .fwd_decl = fwd_decl.toManaged(gpa),
222222 .ctype_pool = ctype_pool.*,
223223 .scratch = .{},
src/link/Coff.zig+7-5
......@@ -1484,14 +1484,16 @@ pub fn updateExports(
14841484 const exported_nav = ip.getNav(exported_nav_index);
14851485 const exported_ty = exported_nav.typeOf(ip);
14861486 if (!ip.isFunctionType(exported_ty)) continue;
1487 const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) {
1488 .x86 => .Stdcall,
1489 else => .C,
1487 const c_cc = target.defaultCCallingConvention().?;
1488 const winapi_cc: std.builtin.NewCallingConvention = switch (target.cpu.arch) {
1489 .x86 => .{ .x86_stdcall = .{} },
1490 else => c_cc,
14901491 };
14911492 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) {
14931495 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) {
14951497 if (exp.opts.name.eqlSlice("WinMain", ip)) {
14961498 zcu.stage1_flags.have_winmain = true;
14971499 } else if (exp.opts.name.eqlSlice("wWinMain", ip)) {
src/link/Dwarf.zig+62-15
......@@ -3398,21 +3398,68 @@ fn updateType(
33983398 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
33993399 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
34003400 try wip_nav.strp(name);
3401 try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
3402 .Unspecified, .C => .normal,
3403 .Naked, .Async, .Inline => .nocall,
3404 .Interrupt, .Signal => .nocall,
3405 .Stdcall => .BORLAND_stdcall,
3406 .Fastcall => .BORLAND_fastcall,
3407 .Vectorcall => .LLVM_vectorcall,
3408 .Thiscall => .BORLAND_thiscall,
3409 .APCS => .nocall,
3410 .AAPCS => .LLVM_AAPCS,
3411 .AAPCSVFP => .LLVM_AAPCS_VFP,
3412 .SysV => .LLVM_X86_64SysV,
3413 .Win64 => .LLVM_Win64,
3414 .Kernel, .Fragment, .Vertex => .nocall,
3415 })));
3401 const cc: DW.CC = cc: {
3402 if (zcu.getTarget().defaultCCallingConvention()) |cc| {
3403 if (@as(std.builtin.NewCallingConvention.Tag, cc) == func_type.cc) {
3404 break :cc .normal;
3405 }
3406 }
3407 break :cc switch (func_type.cc) {
3408 .@"inline" => unreachable,
3409 .@"async", .auto, .naked => .normal,
3410 .x86_64_sysv => .LLVM_X86_64SysV,
3411 .x86_64_win => .LLVM_Win64,
3412 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall,
3413 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
3414 .x86_64_vectorcall => .LLVM_vectorcall,
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));
34163463 try wip_nav.refType(Type.fromInterned(func_type.return_type));
34173464 for (0..func_type.param_types.len) |param_index| {
34183465 try wip_nav.abbrevCode(.func_type_param);
src/link/SpirV.zig+3-4
......@@ -165,10 +165,9 @@ pub fn updateExports(
165165 const target = zcu.getTarget();
166166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
167167 const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {
168 .Vertex => spec.ExecutionModel.Vertex,
169 .Fragment => spec.ExecutionModel.Fragment,
170 .Kernel => spec.ExecutionModel.Kernel,
171 .C => return, // TODO: What to do here?
168 .spirv_vertex => spec.ExecutionModel.Vertex,
169 .spirv_fragment => spec.ExecutionModel.Fragment,
170 .spirv_kernel => spec.ExecutionModel.Kernel,
172171 else => unreachable,
173172 };
174173 const is_vulkan = target.os.tag == .vulkan;
src/target.zig+3-3
......@@ -544,13 +544,13 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 {
544544 };
545545}
546546
547pub fn fnCallConvAllowsZigTypes(target: std.Target, cc: std.builtin.CallingConvention) bool {
547pub fn fnCallConvAllowsZigTypes(cc: std.builtin.NewCallingConvention) bool {
548548 return switch (cc) {
549 .Unspecified, .Async, .Inline => true,
549 .auto, .@"async", .@"inline" => true,
550550 // For now we want to authorize PTX kernel to use zig objects, even if
551551 // we end up exposing the ABI. The goal is to experiment with more
552552 // integrated CPU/GPU code.
553 .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64,
553 .nvptx_kernel => true,
554554 else => false,
555555 };
556556}
src/translate_c.zig+14-14
......@@ -4,7 +4,6 @@ const assert = std.debug.assert;
44const mem = std.mem;
55const math = std.math;
66const meta = std.meta;
7const CallingConvention = std.builtin.CallingConvention;
87const clang = @import("clang.zig");
98const aro = @import("aro");
109const CToken = aro.Tokenizer.Token;
......@@ -5001,17 +5000,18 @@ fn transCC(
50015000 c: *Context,
50025001 fn_ty: *const clang.FunctionType,
50035002 source_loc: clang.SourceLocation,
5004) !CallingConvention {
5003) !ast.Payload.Func.CallingConvention {
50055004 const clang_cc = fn_ty.getCallConv();
5006 switch (clang_cc) {
5007 .C => return CallingConvention.C,
5008 .X86StdCall => return CallingConvention.Stdcall,
5009 .X86FastCall => return CallingConvention.Fastcall,
5010 .X86VectorCall, .AArch64VectorCall => return CallingConvention.Vectorcall,
5011 .X86ThisCall => return CallingConvention.Thiscall,
5012 .AAPCS => return CallingConvention.AAPCS,
5013 .AAPCS_VFP => return CallingConvention.AAPCSVFP,
5014 .X86_64SysV => return CallingConvention.SysV,
5005 return switch (clang_cc) {
5006 .C => .c,
5007 .X86_64SysV => .x86_64_sysv,
5008 .X86StdCall => .x86_stdcall,
5009 .X86FastCall => .x86_fastcall,
5010 .X86ThisCall => .x86_thiscall,
5011 .X86VectorCall => .x86_vectorcall,
5012 .AArch64VectorCall => .aarch64_vfabi,
5013 .AAPCS => .arm_aapcs,
5014 .AAPCS_VFP => .arm_aapcs_vfp,
50155015 else => return fail(
50165016 c,
50175017 error.UnsupportedType,
......@@ -5019,7 +5019,7 @@ fn transCC(
50195019 "unsupported calling convention: {s}",
50205020 .{@tagName(clang_cc)},
50215021 ),
5022 }
5022 };
50235023}
50245024
50255025fn transFnProto(
......@@ -5056,7 +5056,7 @@ fn finishTransFnProto(
50565056 source_loc: clang.SourceLocation,
50575057 fn_decl_context: ?FnDeclContext,
50585058 is_var_args: bool,
5059 cc: CallingConvention,
5059 cc: ast.Payload.Func.CallingConvention,
50605060 is_pub: bool,
50615061) !*ast.Payload.Func {
50625062 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
......@@ -5104,7 +5104,7 @@ fn finishTransFnProto(
51045104
51055105 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
51095109 const return_type_node = blk: {
51105110 if (fn_ty.getNoReturnAttr()) {