diff --git a/lib/zig.h b/lib/zig.h index 139263d11132833d2c64539c2b39cf44b3bd0b89..30e6f3f96a97f47b6648db1d1587bc75c88b6c3f 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -199,10 +199,8 @@ #endif #if defined(zig_msvc) -#define zig_const_arr #define zig_callconv(c) __##c #else -#define zig_const_arr static const #define zig_callconv(c) __attribute__((c)) #endif @@ -5841,11 +5839,6 @@ typedef zig_u128 zig_f80; #define zig_init_special_f80(sign, name, arg, repr) repr #endif -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif #define zig_has_f128 1 #define zig_libc_name_f128(name) name##f128 #define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) @@ -5859,22 +5852,22 @@ typedef struct { uint64_t hi, lo; } zig_f128; #define zig_init_repr_f128(hi, lo) { .h##i = hi, .l##o = lo } #define zig_lo_repr_f128(arg) (arg).lo #define zig_hi_repr_f128(arg) (arg).hi -#elif !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 +#elif FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 +#elif DBL_MANT_DIG == 113 typedef double zig_f128; #define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 +#elif LDBL_MANT_DIG == 113 typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 +#elif FLT128_MANT_DIG == 113 typedef _Float128 zig_f128; #define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 +#elif FLT64X_MANT_DIG == 113 typedef _Float64x zig_f128; #define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) +#elif defined(__SIZEOF_FLOAT128__) typedef __float128 zig_f128; #define zig_make_f128(fp, repr) fp##q #undef zig_make_special_f128 diff --git a/src/Zcu.zig b/src/Zcu.zig index 2af36db254d2edbcfe3ae8a05de265b882d46b01..875ffd44b29c92738f12e3cf32f300301edf2d7d 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -4617,44 +4617,26 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .m68k_rtd, .m68k_interrupt, .msp430_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_aapcs_vfp, - => |opts| opts.incoming_stack_alignment == null, - .arc_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .microblaze_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .mips_interrupt, .mips64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .riscv32_interrupt, .riscv64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .sh_interrupt, - => |opts| opts.incoming_stack_alignment == null, + .avr_interrupt, + .avr_signal, + .ez80_tiflags, + .naked, + => true, // incoming stack alignment supported .x86_sysv, .x86_win, .x86_mingw, .x86_stdcall, - => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, - - .avr_interrupt, - .avr_signal, - => true, - - .ez80_tiflags => true, - - .naked => true, + => |opts| opts.register_params == 0, // incoming stack alignment supported else => false, }; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 1633321426dfc3044177eebe0cd44e6fda3c6aa9..5ab86a9a5fad9e1a4391053bd5e1af970de1feeb 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1750,8 +1750,6 @@ pub const DeclGen = struct { try w.writeAll("zig_no_builtin "); } - if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); - // While incomplete types are usually an acceptable substitute for "void", this is not true // in function return types, where "void" is the only incomplete type permitted. const actual_return_type: Type = .fromInterned(fn_info.return_type); @@ -1763,8 +1761,9 @@ pub const DeclGen = struct { const ret_cty: CType = try .lower(effective_return_type, &dg.ctype_deps, dg.arena, zcu); try w.print("{f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); - if (toCallingConvention(fn_info.cc, zcu)) |call_conv| { - try w.print("zig_callconv({s}) ", .{call_conv}); + switch (CType.CallingConvention.fromLang(fn_info.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), } switch (name) { .nav => |nav| try renderNavName(w, nav, ip), @@ -2221,6 +2220,7 @@ pub fn genLazyCallModifierFn( const fn_val = zcu.navValue(fn_nav); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.print("static zig_{t} ", .{kind}); try dg.renderFunctionSignature(w, fn_val, .none, .definition, switch (kind) { .never_tail => .{ .nav_never_tail = fn_nav }, @@ -2326,8 +2326,10 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E const gpa = f.dg.gpa; const nav_index = f.dg.owner_nav.unwrap().?; const nav_val = zcu.navValue(nav_index); + const fn_info = zcu.typeToFunc(nav_val.typeOf(zcu)).?; const nav = ip.getNav(nav_index); + if (Type.fromInterned(fn_info.return_type).isNoReturn(zcu)) try fwd_decl_writer.writeAll("zig_noreturn "); try fwd_decl_writer.writeAll("static "); try f.dg.renderFunctionSignature( fwd_decl_writer, @@ -2354,6 +2356,35 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E const main_body = f.air.getMainBody(); f.indent(); + if (switch (fn_info.cc) { + inline else => |pl| switch (@TypeOf(pl)) { + void, + std.lang.CallingConvention.SpirvKernelOptions, + std.lang.CallingConvention.SpirvFragmentOptions, + std.lang.CallingConvention.SpirvMeshOptions, + => null, + std.lang.CallingConvention.ArcInterruptOptions, + std.lang.CallingConvention.ArmInterruptOptions, + std.lang.CallingConvention.RiscvInterruptOptions, + std.lang.CallingConvention.ShInterruptOptions, + std.lang.CallingConvention.MicroblazeInterruptOptions, + std.lang.CallingConvention.MipsInterruptOptions, + std.lang.CallingConvention.CommonOptions, + std.lang.CallingConvention.X86RegparmOptions, + => pl.incoming_stack_alignment, + else => @compileError(@tagName(pl)), + }, + }) |incoming_stack_alignment| realign_stack: { + const normal_stack_align = zcu.getTarget().stackAlignment(); + if (incoming_stack_alignment >= normal_stack_align) break :realign_stack; + try header_writer.print("char zig_align({d}) zig_realign_stack;\n ", .{ + normal_stack_align << 1, + }); + try f.code.writer.writeAll( + \\__asm volatile("" :: [zig_realign_stack] "m" (zig_realign_stack)); + ); + try f.newline(); + } try genBodyResolveState(f, undefined, &.{}, main_body, true); try f.outdent(); try f.code.writer.writeByte('}'); @@ -2456,10 +2487,12 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { .@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) { .@"fn" => { + const fn_val: Value = .fromInterned(nav.resolved.?.value); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); try dg.renderFunctionSignature( w, - .fromInterned(nav.resolved.?.value), + fn_val, nav.resolved.?.@"align", .forward_decl, .{ .@"export" = .{ @@ -2560,11 +2593,13 @@ pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indic const exported_val = exported.getValue(zcu); if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| { const @"export" = export_index.ptr(zcu); + const fn_val = exported.getValue(zcu); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); if (@"export".opts.linkage == .weak) try w.writeAll("zig_weak_linkage_fn "); try dg.renderFunctionSignature( w, - exported.getValue(zcu), + fn_val, exported.getAlign(zcu), .forward_decl, .{ .@"export" = .{ @@ -7277,101 +7312,6 @@ fn writeMemoryOrder(w: *Writer, order: std.lang.AtomicOrder) !void { return w.writeAll(toMemoryOrder(order)); } -fn toCallingConvention(cc: std.lang.CallingConvention, zcu: *Zcu) ?[]const u8 { - if (zcu.getTarget().cCallingConvention()) |ccc| { - if (cc.eql(ccc)) { - return null; - } - } - return switch (cc) { - .auto, .naked => null, - - .x86_16_cdecl => "cdecl", - .x86_16_regparmcall => "regparmcall", - .x86_64_sysv, .x86_sysv => "sysv_abi", - .x86_64_win, .x86_win, .x86_mingw => "ms_abi", - .x86_16_stdcall, .x86_stdcall => "stdcall", - .x86_fastcall => "fastcall", - .x86_thiscall => "thiscall", - - .x86_vectorcall, - .x86_64_vectorcall, - => "vectorcall", - - .x86_64_regcall_v3_sysv, - .x86_64_regcall_v4_win, - .x86_regcall_v3, - .x86_regcall_v4_win, - => "regcall", - - .aarch64_vfabi => "aarch64_vector_pcs", - .aarch64_vfabi_sve => "aarch64_sve_pcs", - - .arm_aapcs => "pcs(\"aapcs\")", - .arm_aapcs_vfp => "pcs(\"aapcs-vfp\")", - - .arc_interrupt => |opts| switch (opts.type) { - inline else => |t| "interrupt(\"" ++ @tagName(t) ++ "\")", - }, - - .arm_interrupt => |opts| switch (opts.type) { - .generic => "interrupt", - .irq => "interrupt(\"IRQ\")", - .fiq => "interrupt(\"FIQ\")", - .swi => "interrupt(\"SWI\")", - .abort => "interrupt(\"ABORT\")", - .undef => "interrupt(\"UNDEF\")", - }, - - .avr_signal => "signal", - - .microblaze_interrupt => |opts| switch (opts.type) { - .user => "save_volatiles", - .regular => "interrupt_handler", - .fast => "fast_interrupt", - .breakpoint => "break_handler", - }, - - .mips_interrupt, - .mips64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .riscv64_lp64_v, .riscv32_ilp32_v => "riscv_vector_cc", - - .riscv32_interrupt, - .riscv64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .sh_renesas => "renesas", - .sh_interrupt => |opts| switch (opts.save) { - .fpscr => "trapa_handler", // Implies `interrupt_handler`. - .high => "interrupt_handler, nosave_low_regs", - .full => "interrupt_handler", - .bank => "interrupt_handler, resbank", - }, - - .m68k_rtd => "m68k_rtd", - - .avr_interrupt, - .csky_interrupt, - .m68k_interrupt, - .msp430_interrupt, - .x86_16_interrupt, - .x86_interrupt, - .x86_64_interrupt, - => "interrupt", - - .ez80_tiflags, - => "__tiflags__", - - else => unreachable, // `Zcu.callconvSupported` - }; -} - fn toAtomicRmwSuffix(order: std.lang.AtomicRmwOp) []const u8 { return switch (order) { .Xchg => "xchg", diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index 41ce79a2f5ef333ad5d319f0fbbdd544d9347409..347dc7e16e27dce1c3dd41b006f860f5772fce6c 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -44,8 +44,175 @@ pub const CType = union(enum) { param_tys: []const CType, ret_ty: *const CType, varargs: bool, + cc: CallingConvention, }, + pub const CallingConvention = enum { + c, + + cdecl, + regparmcall, + sysv_abi, + ms_abi, + stdcall, + fastcall, + thiscall, + + vectorcall, + + regcall, + + aarch64_vector_pcs, + aarch64_sve_pcs, + + @"pcs(\"aapcs\")", + @"pcs(\"aapcs-vfp\")", + + @"interrupt(\"ilink1\")", + @"interrupt(\"ilink2\")", + @"interrupt(\"ilink\")", + @"interrupt(\"firq\")", + + interrupt, + @"interrupt(\"IRQ\")", + @"interrupt(\"FIQ\")", + @"interrupt(\"SWI\")", + @"interrupt(\"ABORT\")", + @"interrupt(\"UNDEF\")", + + signal, + + save_volatiles, + interrupt_handler, + fast_interrupt, + break_handler, + + @"interrupt(\"eic\")", + @"interrupt(\"sw0\")", + @"interrupt(\"sw1\")", + @"interrupt(\"hw0\")", + @"interrupt(\"hw1\")", + @"interrupt(\"hw2\")", + @"interrupt(\"hw3\")", + @"interrupt(\"hw4\")", + @"interrupt(\"hw5\")", + + riscv_vector_cc, + @"interrupt(\"supervisor\")", + @"interrupt(\"machine\")", + + renesas, + /// Implies `interrupt_handler`. + trapa_handler, + @"interrupt_handler, nosave_low_regs", + @"interrupt_handler, resbank", + + m68k_rtd, + + tiflags, + + pub fn fromLang(cc: std.lang.CallingConvention, target: *const std.Target) CallingConvention { + if (target.cCallingConvention()) |ccc| { + if (cc.eql(ccc)) { + return .c; + } + } + return switch (cc) { + .auto, .naked => .c, + + .x86_16_cdecl => .cdecl, + .x86_16_regparmcall => .regparmcall, + .x86_64_sysv, .x86_sysv => .sysv_abi, + .x86_64_win, .x86_win, .x86_mingw => .ms_abi, + .x86_16_stdcall, .x86_stdcall => .stdcall, + .x86_fastcall => .fastcall, + .x86_thiscall => .thiscall, + + .x86_vectorcall, + .x86_64_vectorcall, + => .vectorcall, + + .x86_64_regcall_v3_sysv, + .x86_64_regcall_v4_win, + .x86_regcall_v3, + .x86_regcall_v4_win, + => .regcall, + + .aarch64_vfabi => .aarch64_vector_pcs, + .aarch64_vfabi_sve => .aarch64_sve_pcs, + + .arm_aapcs => .@"pcs(\"aapcs\")", + .arm_aapcs_vfp => .@"pcs(\"aapcs-vfp\")", + + .arc_interrupt => |opts| switch (opts.type) { + .ilink1 => .@"interrupt(\"ilink1\")", + .ilink2 => .@"interrupt(\"ilink2\")", + .ilink => .@"interrupt(\"ilink\")", + .firq => .@"interrupt(\"firq\")", + }, + + .arm_interrupt => |opts| switch (opts.type) { + .generic => .interrupt, + .irq => .@"interrupt(\"IRQ\")", + .fiq => .@"interrupt(\"FIQ\")", + .swi => .@"interrupt(\"SWI\")", + .abort => .@"interrupt(\"ABORT\")", + .undef => .@"interrupt(\"UNDEF\")", + }, + + .avr_signal => .signal, + + .microblaze_interrupt => |opts| switch (opts.type) { + .user => .save_volatiles, + .regular => .interrupt_handler, + .fast => .fast_interrupt, + .breakpoint => .break_handler, + }, + + .mips_interrupt, .mips64_interrupt => |opts| switch (opts.mode) { + .eic => .@"interrupt(\"eic\")", + .sw0 => .@"interrupt(\"sw0\")", + .sw1 => .@"interrupt(\"sw1\")", + .hw0 => .@"interrupt(\"hw0\")", + .hw1 => .@"interrupt(\"hw1\")", + .hw2 => .@"interrupt(\"hw2\")", + .hw3 => .@"interrupt(\"hw3\")", + .hw4 => .@"interrupt(\"hw4\")", + .hw5 => .@"interrupt(\"hw5\")", + }, + + .riscv64_lp64_v, .riscv32_ilp32_v => .riscv_vector_cc, + .riscv32_interrupt, .riscv64_interrupt => |opts| switch (opts.mode) { + .supervisor => .@"interrupt(\"supervisor\")", + .machine => .@"interrupt(\"machine\")", + }, + + .sh_renesas => .renesas, + .sh_interrupt => |opts| switch (opts.save) { + .fpscr => .trapa_handler, + .high => .@"interrupt_handler, nosave_low_regs", + .full => .interrupt_handler, + .bank => .@"interrupt_handler, resbank", + }, + + .m68k_rtd => .m68k_rtd, + + .avr_interrupt, + .csky_interrupt, + .m68k_interrupt, + .msp430_interrupt, + .x86_16_interrupt, + .x86_interrupt, + .x86_64_interrupt, + => .interrupt, + + .ez80_tiflags => .tiflags, + + else => unreachable, // `Zcu.callconvSupported` + }; + } + }; + /// Returns `true` if this node has a postfix operator, meaning an `[...]` or `(...)` appears /// after the identifier in a declarator with this type. In this case, if this node is wrapped /// in a pointer type, we will need to add parentheses due to operator precedence. @@ -376,6 +543,7 @@ pub const CType = union(enum) { .ret_ty = ret_cty_buf, .param_tys = param_cty_buf, .varargs = func_type.is_var_args, + .cc = .fromLang(func_type.cc, zcu.getTarget()), } }; } try deps.addType(gpa, cur_ty, allow_incomplete); @@ -763,6 +931,13 @@ pub const CType = union(enum) { try w.writeByte('('); }, } + switch (ptr.elem_ty.*) { + else => {}, + .function => |function| switch (function.cc) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + }, + } try w.writeByte('*'); }, @@ -812,7 +987,7 @@ pub const CType = union(enum) { => {}, .pointer => |ptr| { - // Match opening paren "(" write `writeTypePrefix`. + // Match opening paren "(" in `writeTypePrefix`. switch (ptr.elem_ty.kind()) { .specifier, .pointer => {}, .postfix_op => try w.writeByte(')'), diff --git a/src/codegen/c/type/render_defs.zig b/src/codegen/c/type/render_defs.zig index d591c09bf16d71b77c4d7b2dc3c4659665dd94a1..2ba76d64eda0073dc0cdb032d117fedf16fba0ae 100644 --- a/src/codegen/c/type/render_defs.zig +++ b/src/codegen/c/type/render_defs.zig @@ -203,10 +203,12 @@ pub fn defineComplete( const name_cty: CType = .{ .@"fn" = ty }; const ret_cty: CType = try .lower(effective_ret_ty, deps, arena, zcu); - try w.print("typedef {f}{f}(", .{ - ret_cty.fmtDeclaratorPrefix(zcu), - name_cty.fmtTypeName(zcu), - }); + try w.print("typedef {f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); + switch (CType.CallingConvention.fromLang(func_type.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + } + try w.print("{f}(", .{name_cty.fmtTypeName(zcu)}); var any_params = false; for (func_type.param_types.get(ip)) |param_ty_ip| { const param_ty: Type = .fromInterned(param_ty_ip); @@ -222,9 +224,7 @@ pub fn defineComplete( } else if (!any_params) { try w.writeAll("void"); } - try w.print("){f};", .{ - ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu), - }); + try w.print("){f};", .{ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu)}); break :check_cty null; }, .@"enum" => { @@ -254,7 +254,7 @@ pub fn defineComplete( try w.print( \\{f} {{ \\ {f}ptr{f}; - \\ size_t len; + \\ uintptr_t len; \\}}; , .{ name_cty.fmtTypeName(zcu), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index de5f084008896d56c36ff371078b6581a306a45f..31e67026821a109d79a6e677014fa0bcf8712615 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2550,7 +2550,7 @@ pub const Object = struct { llvm_function.setCallConv(cc_info.llvm_cc, &o.builder); if (cc_info.align_stack) { - try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); + try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("stackrealign"), .value = .empty } }, &o.builder); } if (cc_info.naked) { @@ -4522,7 +4522,7 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) std.lang.CallingConvention.SpirvFragmentOptions, std.lang.CallingConvention.SpirvMeshOptions, => .{ null, 0, 0 }, - else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), + else => @compileError("TODO: toLlvmCallConv(." ++ @tagName(pl) ++ ")"), }, }; return .{