| ... | @@ -2718,73 +2718,60 @@ pub const Object = struct { | ... | @@ -2718,73 +2718,60 @@ pub const Object = struct { |
| 2718 | @panic("TODO: LLVM backend lower async function"); | 2718 | @panic("TODO: LLVM backend lower async function"); |
| 2719 | } | 2719 | } |
| 2720 | | 2720 | |
| 2721 | { | 2721 | const cc_info = toLlvmCallConv(fn_info.cc, target).?; |
| 2722 | const cc_info = toLlvmCallConv(fn_info.cc, target).?; | | |
| 2723 | | 2722 | |
| 2724 | function_index.setCallConv(cc_info.llvm_cc, &o.builder); | 2723 | function_index.setCallConv(cc_info.llvm_cc, &o.builder); |
| 2725 | | 2724 | |
| 2726 | if (cc_info.align_stack) { | 2725 | if (cc_info.align_stack) { |
| 2727 | try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); | 2726 | try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); |
| 2728 | } else { | 2727 | } |
| 2729 | _ = try attributes.removeFnAttr(.alignstack); | | |
| 2730 | } | | |
| 2731 | | | |
| 2732 | if (cc_info.naked) { | | |
| 2733 | try attributes.addFnAttr(.naked, &o.builder); | | |
| 2734 | } else { | | |
| 2735 | _ = try attributes.removeFnAttr(.naked); | | |
| 2736 | } | | |
| 2737 | | 2728 | |
| 2738 | for (0..cc_info.inreg_param_count) |param_idx| { | 2729 | if (cc_info.naked) { |
| 2739 | try attributes.addParamAttr(param_idx, .inreg, &o.builder); | 2730 | try attributes.addFnAttr(.naked, &o.builder); |
| 2740 | } | 2731 | } |
| 2741 | for (cc_info.inreg_param_count..std.math.maxInt(u2)) |param_idx| { | | |
| 2742 | _ = try attributes.removeParamAttr(param_idx, .inreg); | | |
| 2743 | } | | |
| 2744 | | 2732 | |
| 2745 | switch (fn_info.cc) { | 2733 | switch (fn_info.cc) { |
| 2746 | inline .riscv64_interrupt, | 2734 | inline .riscv64_interrupt, |
| 2747 | .riscv32_interrupt, | 2735 | .riscv32_interrupt, |
| 2748 | .mips_interrupt, | 2736 | .mips_interrupt, |
| 2749 | .mips64_interrupt, | 2737 | .mips64_interrupt, |
| 2750 | => |info| { | 2738 | => |info| { |
| 2751 | try attributes.addFnAttr(.{ .string = .{ | 2739 | try attributes.addFnAttr(.{ .string = .{ |
| 2752 | .kind = try o.builder.string("interrupt"), | 2740 | .kind = try o.builder.string("interrupt"), |
| 2753 | .value = try o.builder.string(@tagName(info.mode)), | 2741 | .value = try o.builder.string(@tagName(info.mode)), |
| 2754 | } }, &o.builder); | 2742 | } }, &o.builder); |
| 2755 | }, | 2743 | }, |
| 2756 | .arm_interrupt, | 2744 | .arm_interrupt, |
| 2757 | => |info| { | 2745 | => |info| { |
| 2758 | try attributes.addFnAttr(.{ .string = .{ | 2746 | try attributes.addFnAttr(.{ .string = .{ |
| 2759 | .kind = try o.builder.string("interrupt"), | 2747 | .kind = try o.builder.string("interrupt"), |
| 2760 | .value = try o.builder.string(switch (info.type) { | 2748 | .value = try o.builder.string(switch (info.type) { |
| 2761 | .generic => "", | 2749 | .generic => "", |
| 2762 | .irq => "IRQ", | 2750 | .irq => "IRQ", |
| 2763 | .fiq => "FIQ", | 2751 | .fiq => "FIQ", |
| 2764 | .swi => "SWI", | 2752 | .swi => "SWI", |
| 2765 | .abort => "ABORT", | 2753 | .abort => "ABORT", |
| 2766 | .undef => "UNDEF", | 2754 | .undef => "UNDEF", |
| 2767 | }), | 2755 | }), |
| 2768 | } }, &o.builder); | 2756 | } }, &o.builder); |
| 2769 | }, | 2757 | }, |
| 2770 | // these function attributes serve as a backup against any mistakes LLVM makes. | 2758 | // these function attributes serve as a backup against any mistakes LLVM makes. |
| 2771 | // clang sets both the function's calling convention and the function attributes | 2759 | // clang sets both the function's calling convention and the function attributes |
| 2772 | // in its backend, so future patches to the AVR backend could end up checking only one, | 2760 | // in its backend, so future patches to the AVR backend could end up checking only one, |
| 2773 | // possibly breaking our support. it's safer to just emit both. | 2761 | // possibly breaking our support. it's safer to just emit both. |
| 2774 | .avr_interrupt, .avr_signal, .csky_interrupt => { | 2762 | .avr_interrupt, .avr_signal, .csky_interrupt => { |
| 2775 | try attributes.addFnAttr(.{ .string = .{ | 2763 | try attributes.addFnAttr(.{ .string = .{ |
| 2776 | .kind = try o.builder.string(switch (fn_info.cc) { | 2764 | .kind = try o.builder.string(switch (fn_info.cc) { |
| 2777 | .avr_interrupt, | 2765 | .avr_interrupt, |
| 2778 | .csky_interrupt, | 2766 | .csky_interrupt, |
| 2779 | => "interrupt", | 2767 | => "interrupt", |
| 2780 | .avr_signal => "signal", | 2768 | .avr_signal => "signal", |
| 2781 | else => unreachable, | 2769 | else => unreachable, |
| 2782 | }), | 2770 | }), |
| 2783 | .value = .empty, | 2771 | .value = .empty, |
| 2784 | } }, &o.builder); | 2772 | } }, &o.builder); |
| 2785 | }, | 2773 | }, |
| 2786 | else => {}, | 2774 | else => {}, |
| 2787 | } | | |
| 2788 | } | 2775 | } |
| 2789 | | 2776 | |
| 2790 | // Function attributes that are independent of analysis results of the function body. | 2777 | // Function attributes that are independent of analysis results of the function body. |
| ... | @@ -2821,6 +2808,10 @@ pub const Object = struct { | ... | @@ -2821,6 +2808,10 @@ pub const Object = struct { |
| 2821 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); | 2808 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); |
| 2822 | it.llvm_index += 1; | 2809 | it.llvm_index += 1; |
| 2823 | } | 2810 | } |
| | 2811 | |
| | 2812 | var remaining_inreg_int = cc_info.inreg_int_params; |
| | 2813 | var remaining_inreg_float = cc_info.inreg_float_params; |
| | 2814 | |
| 2824 | while (try it.next()) |lowering| switch (lowering) { | 2815 | while (try it.next()) |lowering| switch (lowering) { |
| 2825 | .byval => { | 2816 | .byval => { |
| 2826 | const param_index = it.zig_index - 1; | 2817 | const param_index = it.zig_index - 1; |
| ... | @@ -2828,6 +2819,21 @@ pub const Object = struct { | ... | @@ -2828,6 +2819,21 @@ pub const Object = struct { |
| 2828 | if (!isByRef(param_ty, zcu)) { | 2819 | if (!isByRef(param_ty, zcu)) { |
| 2829 | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); | 2820 | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 2830 | } | 2821 | } |
| | 2822 | |
| | 2823 | if (remaining_inreg_int > 0 and |
| | 2824 | (param_ty.isPtrAtRuntime(zcu) or |
| | 2825 | (param_ty.isAbiInt(zcu) and param_ty.abiSize(zcu) <= Type.usize.abiSize(zcu)))) |
| | 2826 | { |
| | 2827 | try attributes.addParamAttr(it.llvm_index - 1, .inreg, &o.builder); |
| | 2828 | remaining_inreg_int -= 1; |
| | 2829 | } |
| | 2830 | |
| | 2831 | if (remaining_inreg_float > 0 and |
| | 2832 | param_ty.zigTypeTag(zcu) == .float) |
| | 2833 | { |
| | 2834 | try attributes.addParamAttr(it.llvm_index - 1, .inreg, &o.builder); |
| | 2835 | remaining_inreg_float -= 1; |
| | 2836 | } |
| 2831 | }, | 2837 | }, |
| 2832 | .byref => { | 2838 | .byref => { |
| 2833 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 2839 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| ... | @@ -4379,15 +4385,19 @@ const CallingConventionInfo = struct { | ... | @@ -4379,15 +4385,19 @@ const CallingConventionInfo = struct { |
| 4379 | align_stack: bool, | 4385 | align_stack: bool, |
| 4380 | /// Whether the function needs a `naked` attribute. | 4386 | /// Whether the function needs a `naked` attribute. |
| 4381 | naked: bool, | 4387 | naked: bool, |
| 4382 | /// How many leading parameters to apply the `inreg` attribute to. | 4388 | /// How many leading register-sized integer parameters to apply the `inreg` attribute to. |
| 4383 | inreg_param_count: u2 = 0, | 4389 | inreg_int_params: u2 = 0, |
| | 4390 | /// How many leading floating-point parameters to apply the `inreg` attribute to. |
| | 4391 | inreg_float_params: u3 = 0, |
| 4384 | }; | 4392 | }; |
| 4385 | | 4393 | |
| 4386 | pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) ?CallingConventionInfo { | 4394 | pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) ?CallingConventionInfo { |
| 4387 | const llvm_cc = toLlvmCallConvTag(cc, target) orelse return null; | 4395 | const llvm_cc = toLlvmCallConvTag(cc, target) orelse return null; |
| 4388 | const incoming_stack_alignment: ?u64, const register_params: u2 = switch (cc) { | 4396 | const incoming_stack_alignment: ?u64, const inreg_int_params: u2, const inreg_float_params: u3 = switch (cc) { |
| | 4397 | .x86_fastcall => |opts| .{ opts.incoming_stack_alignment, 2, 0 }, |
| | 4398 | .x86_vectorcall => |opts| .{ opts.incoming_stack_alignment, 2, 6 }, |
| 4389 | inline else => |pl| switch (@TypeOf(pl)) { | 4399 | inline else => |pl| switch (@TypeOf(pl)) { |
| 4390 | void => .{ null, 0 }, | 4400 | void => .{ null, 0, 0 }, |
| 4391 | std.lang.CallingConvention.ArcInterruptOptions, | 4401 | std.lang.CallingConvention.ArcInterruptOptions, |
| 4392 | std.lang.CallingConvention.ArmInterruptOptions, | 4402 | std.lang.CallingConvention.ArmInterruptOptions, |
| 4393 | std.lang.CallingConvention.RiscvInterruptOptions, | 4403 | std.lang.CallingConvention.RiscvInterruptOptions, |
| ... | @@ -4395,8 +4405,8 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) | ... | @@ -4395,8 +4405,8 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) |
| 4395 | std.lang.CallingConvention.MicroblazeInterruptOptions, | 4405 | std.lang.CallingConvention.MicroblazeInterruptOptions, |
| 4396 | std.lang.CallingConvention.MipsInterruptOptions, | 4406 | std.lang.CallingConvention.MipsInterruptOptions, |
| 4397 | std.lang.CallingConvention.CommonOptions, | 4407 | std.lang.CallingConvention.CommonOptions, |
| 4398 | => .{ pl.incoming_stack_alignment, 0 }, | 4408 | => .{ pl.incoming_stack_alignment, 0, 0 }, |
| 4399 | std.lang.CallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params }, | 4409 | std.lang.CallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params, 0 }, |
| 4400 | else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), | 4410 | else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), |
| 4401 | }, | 4411 | }, |
| 4402 | }; | 4412 | }; |
| ... | @@ -4407,7 +4417,8 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) | ... | @@ -4407,7 +4417,8 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) |
| 4407 | break :need_align a < normal_stack_align; | 4417 | break :need_align a < normal_stack_align; |
| 4408 | } else false, | 4418 | } else false, |
| 4409 | .naked = cc == .naked, | 4419 | .naked = cc == .naked, |
| 4410 | .inreg_param_count = register_params, | 4420 | .inreg_int_params = inreg_int_params, |
| | 4421 | .inreg_float_params = inreg_float_params, |
| 4411 | }; | 4422 | }; |
| 4412 | } | 4423 | } |
| 4413 | pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const std.Target) ?Builder.CallConv { | 4424 | pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const std.Target) ?Builder.CallConv { |