| ... | @@ -58,6 +58,15 @@ target: *const std.Target, | ... | @@ -58,6 +58,15 @@ target: *const std.Target, |
| 58 | owner: Owner, | 58 | owner: Owner, |
| 59 | err_msg: ?*ErrorMsg, | 59 | err_msg: ?*ErrorMsg, |
| 60 | args: []MCValue, | 60 | args: []MCValue, |
| | 61 | va_info: union { |
| | 62 | sysv: struct { |
| | 63 | gp_count: u32, |
| | 64 | fp_count: u32, |
| | 65 | overflow_arg_area: FrameAddr, |
| | 66 | reg_save_area: FrameAddr, |
| | 67 | }, |
| | 68 | win64: struct {}, |
| | 69 | }, |
| 61 | ret_mcv: InstTracking, | 70 | ret_mcv: InstTracking, |
| 62 | fn_type: Type, | 71 | fn_type: Type, |
| 63 | arg_index: u32, | 72 | arg_index: u32, |
| ... | @@ -745,6 +754,7 @@ pub fn generate( | ... | @@ -745,6 +754,7 @@ pub fn generate( |
| 745 | .owner = .{ .func_index = func_index }, | 754 | .owner = .{ .func_index = func_index }, |
| 746 | .err_msg = null, | 755 | .err_msg = null, |
| 747 | .args = undefined, // populated after `resolveCallingConventionValues` | 756 | .args = undefined, // populated after `resolveCallingConventionValues` |
| | 757 | .va_info = undefined, // populated after `resolveCallingConventionValues` |
| 748 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` | 758 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` |
| 749 | .fn_type = fn_type, | 759 | .fn_type = fn_type, |
| 750 | .arg_index = 0, | 760 | .arg_index = 0, |
| ... | @@ -785,6 +795,7 @@ pub fn generate( | ... | @@ -785,6 +795,7 @@ pub fn generate( |
| 785 | ); | 795 | ); |
| 786 | | 796 | |
| 787 | const fn_info = mod.typeToFunc(fn_type).?; | 797 | const fn_info = mod.typeToFunc(fn_type).?; |
| | 798 | const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*); |
| 788 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { | 799 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { |
| 789 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, | 800 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 790 | error.OutOfRegisters => return Result{ | 801 | error.OutOfRegisters => return Result{ |
| ... | @@ -819,6 +830,16 @@ pub fn generate( | ... | @@ -819,6 +830,16 @@ pub fn generate( |
| 819 | .alignment = call_info.stack_align, | 830 | .alignment = call_info.stack_align, |
| 820 | }), | 831 | }), |
| 821 | ); | 832 | ); |
| | 833 | function.va_info = switch (cc) { |
| | 834 | .SysV => .{ .sysv = .{ |
| | 835 | .gp_count = call_info.gp_count, |
| | 836 | .fp_count = call_info.fp_count, |
| | 837 | .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count }, |
| | 838 | .reg_save_area = undefined, |
| | 839 | } }, |
| | 840 | .Win64 => .{ .win64 = .{} }, |
| | 841 | else => undefined, |
| | 842 | }; |
| 822 | | 843 | |
| 823 | function.gen() catch |err| switch (err) { | 844 | function.gen() catch |err| switch (err) { |
| 824 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, | 845 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| ... | @@ -839,7 +860,7 @@ pub fn generate( | ... | @@ -839,7 +860,7 @@ pub fn generate( |
| 839 | .lower = .{ | 860 | .lower = .{ |
| 840 | .allocator = bin_file.allocator, | 861 | .allocator = bin_file.allocator, |
| 841 | .mir = mir, | 862 | .mir = mir, |
| 842 | .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*), | 863 | .cc = cc, |
| 843 | .src_loc = src_loc, | 864 | .src_loc = src_loc, |
| 844 | }, | 865 | }, |
| 845 | .bin_file = bin_file, | 866 | .bin_file = bin_file, |
| ... | @@ -894,6 +915,7 @@ pub fn generateLazy( | ... | @@ -894,6 +915,7 @@ pub fn generateLazy( |
| 894 | .owner = .{ .lazy_sym = lazy_sym }, | 915 | .owner = .{ .lazy_sym = lazy_sym }, |
| 895 | .err_msg = null, | 916 | .err_msg = null, |
| 896 | .args = undefined, | 917 | .args = undefined, |
| | 918 | .va_info = undefined, |
| 897 | .ret_mcv = undefined, | 919 | .ret_mcv = undefined, |
| 898 | .fn_type = undefined, | 920 | .fn_type = undefined, |
| 899 | .arg_index = undefined, | 921 | .arg_index = undefined, |
| ... | @@ -1660,7 +1682,8 @@ fn asmMemoryRegisterImmediate( | ... | @@ -1660,7 +1682,8 @@ fn asmMemoryRegisterImmediate( |
| 1660 | | 1682 | |
| 1661 | fn gen(self: *Self) InnerError!void { | 1683 | fn gen(self: *Self) InnerError!void { |
| 1662 | const mod = self.bin_file.options.module.?; | 1684 | const mod = self.bin_file.options.module.?; |
| 1663 | const cc = self.fn_type.fnCallingConvention(mod); | 1685 | const fn_info = mod.typeToFunc(self.fn_type).?; |
| | 1686 | const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 1664 | if (cc != .Naked) { | 1687 | if (cc != .Naked) { |
| 1665 | try self.asmRegister(.{ ._, .push }, .rbp); | 1688 | try self.asmRegister(.{ ._, .push }, .rbp); |
| 1666 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); | 1689 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); |
| ... | @@ -1690,6 +1713,42 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -1690,6 +1713,42 @@ fn gen(self: *Self) InnerError!void { |
| 1690 | else => unreachable, | 1713 | else => unreachable, |
| 1691 | } | 1714 | } |
| 1692 | | 1715 | |
| | 1716 | if (fn_info.is_var_args) switch (cc) { |
| | 1717 | .SysV => { |
| | 1718 | const info = &self.va_info.sysv; |
| | 1719 | const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{ |
| | 1720 | .size = abi.SysV.c_abi_int_param_regs.len * 8 + |
| | 1721 | abi.SysV.c_abi_sse_param_regs.len * 16, |
| | 1722 | .alignment = .@"16", |
| | 1723 | })); |
| | 1724 | info.reg_save_area = .{ .index = reg_save_area_fi }; |
| | 1725 | |
| | 1726 | for (abi.SysV.c_abi_int_param_regs[info.gp_count..], info.gp_count..) |reg, reg_i| |
| | 1727 | try self.genSetMem( |
| | 1728 | .{ .frame = reg_save_area_fi }, |
| | 1729 | @intCast(reg_i * 8), |
| | 1730 | Type.usize, |
| | 1731 | .{ .register = reg }, |
| | 1732 | ); |
| | 1733 | |
| | 1734 | try self.asmRegisterImmediate(.{ ._, .cmp }, .al, Immediate.u(info.fp_count)); |
| | 1735 | const skip_sse_reloc = try self.asmJccReloc(undefined, .na); |
| | 1736 | |
| | 1737 | const vec_2_f64 = try mod.vectorType(.{ .len = 2, .child = .f64_type }); |
| | 1738 | for (abi.SysV.c_abi_sse_param_regs[info.fp_count..], info.fp_count..) |reg, reg_i| |
| | 1739 | try self.genSetMem( |
| | 1740 | .{ .frame = reg_save_area_fi }, |
| | 1741 | @intCast(abi.SysV.c_abi_int_param_regs.len * 8 + reg_i * 16), |
| | 1742 | vec_2_f64, |
| | 1743 | .{ .register = reg }, |
| | 1744 | ); |
| | 1745 | |
| | 1746 | try self.performReloc(skip_sse_reloc); |
| | 1747 | }, |
| | 1748 | .Win64 => return self.fail("TODO implement gen var arg function for Win64", .{}), |
| | 1749 | else => unreachable, |
| | 1750 | }; |
| | 1751 | |
| 1693 | try self.asmPseudo(.pseudo_dbg_prologue_end_none); | 1752 | try self.asmPseudo(.pseudo_dbg_prologue_end_none); |
| 1694 | | 1753 | |
| 1695 | try self.genBody(self.air.getMainBody()); | 1754 | try self.genBody(self.air.getMainBody()); |
| ... | @@ -2064,10 +2123,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2064,10 +2123,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2064 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | 2123 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 2065 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), | 2124 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 2066 | | 2125 | |
| 2067 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), | 2126 | .c_va_arg => try self.airVaArg(inst), |
| 2068 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), | 2127 | .c_va_copy => try self.airVaCopy(inst), |
| 2069 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), | 2128 | .c_va_end => try self.airVaEnd(inst), |
| 2070 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), | 2129 | .c_va_start => try self.airVaStart(inst), |
| 2071 | | 2130 | |
| 2072 | .wasm_memory_size => unreachable, | 2131 | .wasm_memory_size => unreachable, |
| 2073 | .wasm_memory_grow => unreachable, | 2132 | .wasm_memory_grow => unreachable, |
| ... | @@ -2105,7 +2164,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2105,7 +2164,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2105 | switch (lazy_sym.ty.zigTypeTag(mod)) { | 2164 | switch (lazy_sym.ty.zigTypeTag(mod)) { |
| 2106 | .Enum => { | 2165 | .Enum => { |
| 2107 | const enum_ty = lazy_sym.ty; | 2166 | const enum_ty = lazy_sym.ty; |
| 2108 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); | 2167 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(mod)}); |
| 2109 | | 2168 | |
| 2110 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); | 2169 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); |
| 2111 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); | 2170 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| ... | @@ -2153,7 +2212,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2153,7 +2212,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2153 | }, | 2212 | }, |
| 2154 | else => return self.fail( | 2213 | else => return self.fail( |
| 2155 | "TODO implement {s} for {}", | 2214 | "TODO implement {s} for {}", |
| 2156 | .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) }, | 2215 | .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) }, |
| 2157 | ), | 2216 | ), |
| 2158 | } | 2217 | } |
| 2159 | } | 2218 | } |
| ... | @@ -2914,9 +2973,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2914,9 +2973,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2914 | else => null, | 2973 | else => null, |
| 2915 | }, | 2974 | }, |
| 2916 | else => null, | 2975 | else => null, |
| 2917 | }) orelse return self.fail("TODO implement airTrunc for {}", .{ | 2976 | }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(mod)}); |
| 2918 | dst_ty.fmt(self.bin_file.options.module.?), | | |
| 2919 | }); | | |
| 2920 | | 2977 | |
| 2921 | const elem_ty = src_ty.childType(mod); | 2978 | const elem_ty = src_ty.childType(mod); |
| 2922 | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); | 2979 | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); |
| ... | @@ -4568,7 +4625,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4568,7 +4625,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4568 | .{ .immediate = 128 - src_bits }, | 4625 | .{ .immediate = 128 - src_bits }, |
| 4569 | ); | 4626 | ); |
| 4570 | } | 4627 | } |
| 4571 | } else return self.fail("TODO airClz of {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 4628 | } else return self.fail("TODO airClz of {}", .{src_ty.fmt(mod)}); |
| 4572 | break :result dst_mcv; | 4629 | break :result dst_mcv; |
| 4573 | } | 4630 | } |
| 4574 | | 4631 | |
| ... | @@ -4697,12 +4754,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4697,12 +4754,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4697 | try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 }); | 4754 | try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 }); |
| 4698 | try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv); | 4755 | try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv); |
| 4699 | try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc); | 4756 | try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc); |
| 4700 | } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 4757 | } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(mod)}); |
| 4701 | break :result dst_mcv; | 4758 | break :result dst_mcv; |
| 4702 | } | 4759 | } |
| 4703 | | 4760 | |
| 4704 | if (src_bits > 64) | 4761 | if (src_bits > 64) return self.fail("TODO airCtz of {}", .{src_ty.fmt(mod)}); |
| 4705 | return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | | |
| 4706 | | 4762 | |
| 4707 | const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits }); | 4763 | const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits }); |
| 4708 | const width_lock = self.register_manager.lockRegAssumeUnused(width_reg); | 4764 | const width_lock = self.register_manager.lockRegAssumeUnused(width_reg); |
| ... | @@ -5129,9 +5185,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) | ... | @@ -5129,9 +5185,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) |
| 5129 | .abs => .{ .v_pd, .@"and" }, | 5185 | .abs => .{ .v_pd, .@"and" }, |
| 5130 | else => unreachable, | 5186 | else => unreachable, |
| 5131 | }, | 5187 | }, |
| 5132 | 80 => return self.fail("TODO implement floatSign for {}", .{ | 5188 | 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(mod)}), |
| 5133 | ty.fmt(self.bin_file.options.module.?), | | |
| 5134 | }), | | |
| 5135 | else => unreachable, | 5189 | else => unreachable, |
| 5136 | }, | 5190 | }, |
| 5137 | registerAlias(dst_reg, abi_size), | 5191 | registerAlias(dst_reg, abi_size), |
| ... | @@ -5157,9 +5211,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) | ... | @@ -5157,9 +5211,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) |
| 5157 | .abs => .{ ._pd, .@"and" }, | 5211 | .abs => .{ ._pd, .@"and" }, |
| 5158 | else => unreachable, | 5212 | else => unreachable, |
| 5159 | }, | 5213 | }, |
| 5160 | 80 => return self.fail("TODO implement floatSign for {}", .{ | 5214 | 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(mod)}), |
| 5161 | ty.fmt(self.bin_file.options.module.?), | | |
| 5162 | }), | | |
| 5163 | else => unreachable, | 5215 | else => unreachable, |
| 5164 | }, | 5216 | }, |
| 5165 | registerAlias(dst_reg, abi_size), | 5217 | registerAlias(dst_reg, abi_size), |
| ... | @@ -5242,9 +5294,8 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro | ... | @@ -5242,9 +5294,8 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 5242 | }, | 5294 | }, |
| 5243 | else => unreachable, | 5295 | else => unreachable, |
| 5244 | } else null) orelse { | 5296 | } else null) orelse { |
| 5245 | if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement genRound for {}", .{ | 5297 | if (ty.zigTypeTag(mod) != .Float) |
| 5246 | ty.fmt(self.bin_file.options.module.?), | 5298 | return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)}); |
| 5247 | }); | | |
| 5248 | | 5299 | |
| 5249 | var callee: ["__trunc?".len]u8 = undefined; | 5300 | var callee: ["__trunc?".len]u8 = undefined; |
| 5250 | const res = try self.genCall(.{ .lib = .{ | 5301 | const res = try self.genCall(.{ .lib = .{ |
| ... | @@ -5596,9 +5647,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn | ... | @@ -5596,9 +5647,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn |
| 5596 | const val_bit_off = ptr_info.packed_offset.bit_offset % limb_abi_bits; | 5647 | const val_bit_off = ptr_info.packed_offset.bit_offset % limb_abi_bits; |
| 5597 | const val_extra_bits = self.regExtraBits(val_ty); | 5648 | const val_extra_bits = self.regExtraBits(val_ty); |
| 5598 | | 5649 | |
| 5599 | if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{ | 5650 | if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{val_ty.fmt(mod)}); |
| 5600 | val_ty.fmt(self.bin_file.options.module.?), | | |
| 5601 | }); | | |
| 5602 | | 5651 | |
| 5603 | const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); | 5652 | const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); |
| 5604 | const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg); | 5653 | const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg); |
| ... | @@ -5800,9 +5849,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In | ... | @@ -5800,9 +5849,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 5800 | limb_mem, | 5849 | limb_mem, |
| 5801 | registerAlias(tmp_reg, limb_abi_size), | 5850 | registerAlias(tmp_reg, limb_abi_size), |
| 5802 | ); | 5851 | ); |
| 5803 | } else return self.fail("TODO: implement packed store of {}", .{ | 5852 | } else return self.fail("TODO: implement packed store of {}", .{src_ty.fmt(mod)}); |
| 5804 | src_ty.fmt(self.bin_file.options.module.?), | | |
| 5805 | }); | | |
| 5806 | } | 5853 | } |
| 5807 | } | 5854 | } |
| 5808 | | 5855 | |
| ... | @@ -6108,9 +6155,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: | ... | @@ -6108,9 +6155,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 6108 | const mod = self.bin_file.options.module.?; | 6155 | const mod = self.bin_file.options.module.?; |
| 6109 | const src_ty = self.typeOf(src_air); | 6156 | const src_ty = self.typeOf(src_air); |
| 6110 | const src_mcv = try self.resolveInst(src_air); | 6157 | const src_mcv = try self.resolveInst(src_air); |
| 6111 | if (src_ty.zigTypeTag(mod) == .Vector) { | 6158 | if (src_ty.zigTypeTag(mod) == .Vector) |
| 6112 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 6159 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(mod)}); |
| 6113 | } | | |
| 6114 | | 6160 | |
| 6115 | switch (src_mcv) { | 6161 | switch (src_mcv) { |
| 6116 | .eflags => |cc| switch (tag) { | 6162 | .eflags => |cc| switch (tag) { |
| ... | @@ -6170,10 +6216,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: | ... | @@ -6170,10 +6216,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 6170 | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { | 6216 | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { |
| 6171 | const mod = self.bin_file.options.module.?; | 6217 | const mod = self.bin_file.options.module.?; |
| 6172 | const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); | 6218 | const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 6173 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ | 6219 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(mod) }); |
| 6174 | mir_tag, | | |
| 6175 | dst_ty.fmt(self.bin_file.options.module.?), | | |
| 6176 | }); | | |
| 6177 | switch (dst_mcv) { | 6220 | switch (dst_mcv) { |
| 6178 | .none, | 6221 | .none, |
| 6179 | .unreach, | 6222 | .unreach, |
| ... | @@ -6529,7 +6572,7 @@ fn genMulDivBinOp( | ... | @@ -6529,7 +6572,7 @@ fn genMulDivBinOp( |
| 6529 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, | 6572 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| 6530 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, | 6573 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, |
| 6531 | } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{ | 6574 | } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{ |
| 6532 | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), | 6575 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 6533 | }); | 6576 | }); |
| 6534 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; | 6577 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; |
| 6535 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; | 6578 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; |
| ... | @@ -6720,7 +6763,7 @@ fn genBinOp( | ... | @@ -6720,7 +6763,7 @@ fn genBinOp( |
| 6720 | floatLibcAbiSuffix(lhs_ty), | 6763 | floatLibcAbiSuffix(lhs_ty), |
| 6721 | }), | 6764 | }), |
| 6722 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ | 6765 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 6723 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 6766 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 6724 | }), | 6767 | }), |
| 6725 | } catch unreachable, | 6768 | } catch unreachable, |
| 6726 | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }); | 6769 | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }); |
| ... | @@ -6743,7 +6786,7 @@ fn genBinOp( | ... | @@ -6743,7 +6786,7 @@ fn genBinOp( |
| 6743 | abi_size, | 6786 | abi_size, |
| 6744 | ) else null, | 6787 | ) else null, |
| 6745 | .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{ | 6788 | .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 6746 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 6789 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 6747 | }), | 6790 | }), |
| 6748 | }; | 6791 | }; |
| 6749 | const mask_lock = | 6792 | const mask_lock = |
| ... | @@ -6980,7 +7023,7 @@ fn genBinOp( | ... | @@ -6980,7 +7023,7 @@ fn genBinOp( |
| 6980 | }, | 7023 | }, |
| 6981 | | 7024 | |
| 6982 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ | 7025 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 6983 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7026 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 6984 | }), | 7027 | }), |
| 6985 | } | 7028 | } |
| 6986 | return dst_mcv; | 7029 | return dst_mcv; |
| ... | @@ -7567,7 +7610,7 @@ fn genBinOp( | ... | @@ -7567,7 +7610,7 @@ fn genBinOp( |
| 7567 | }, | 7610 | }, |
| 7568 | }, | 7611 | }, |
| 7569 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7612 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7570 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7613 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7571 | }); | 7614 | }); |
| 7572 | | 7615 | |
| 7573 | const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias( | 7616 | const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias( |
| ... | @@ -7653,7 +7696,7 @@ fn genBinOp( | ... | @@ -7653,7 +7696,7 @@ fn genBinOp( |
| 7653 | }, | 7696 | }, |
| 7654 | else => unreachable, | 7697 | else => unreachable, |
| 7655 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7698 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7656 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7699 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7657 | }), | 7700 | }), |
| 7658 | mask_reg, | 7701 | mask_reg, |
| 7659 | rhs_copy_reg, | 7702 | rhs_copy_reg, |
| ... | @@ -7685,7 +7728,7 @@ fn genBinOp( | ... | @@ -7685,7 +7728,7 @@ fn genBinOp( |
| 7685 | }, | 7728 | }, |
| 7686 | else => unreachable, | 7729 | else => unreachable, |
| 7687 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7730 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7688 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7731 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7689 | }), | 7732 | }), |
| 7690 | dst_reg, | 7733 | dst_reg, |
| 7691 | dst_reg, | 7734 | dst_reg, |
| ... | @@ -7721,7 +7764,7 @@ fn genBinOp( | ... | @@ -7721,7 +7764,7 @@ fn genBinOp( |
| 7721 | }, | 7764 | }, |
| 7722 | else => unreachable, | 7765 | else => unreachable, |
| 7723 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7766 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7724 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7767 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7725 | }), | 7768 | }), |
| 7726 | mask_reg, | 7769 | mask_reg, |
| 7727 | mask_reg, | 7770 | mask_reg, |
| ... | @@ -7752,7 +7795,7 @@ fn genBinOp( | ... | @@ -7752,7 +7795,7 @@ fn genBinOp( |
| 7752 | }, | 7795 | }, |
| 7753 | else => unreachable, | 7796 | else => unreachable, |
| 7754 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7797 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7755 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7798 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7756 | }), | 7799 | }), |
| 7757 | dst_reg, | 7800 | dst_reg, |
| 7758 | lhs_copy_reg.?, | 7801 | lhs_copy_reg.?, |
| ... | @@ -7783,7 +7826,7 @@ fn genBinOp( | ... | @@ -7783,7 +7826,7 @@ fn genBinOp( |
| 7783 | }, | 7826 | }, |
| 7784 | else => unreachable, | 7827 | else => unreachable, |
| 7785 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7828 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7786 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7829 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7787 | }), | 7830 | }), |
| 7788 | dst_reg, | 7831 | dst_reg, |
| 7789 | mask_reg, | 7832 | mask_reg, |
| ... | @@ -7813,7 +7856,7 @@ fn genBinOp( | ... | @@ -7813,7 +7856,7 @@ fn genBinOp( |
| 7813 | }, | 7856 | }, |
| 7814 | else => unreachable, | 7857 | else => unreachable, |
| 7815 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7858 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7816 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7859 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7817 | }), | 7860 | }), |
| 7818 | mask_reg, | 7861 | mask_reg, |
| 7819 | lhs_copy_reg.?, | 7862 | lhs_copy_reg.?, |
| ... | @@ -7843,7 +7886,7 @@ fn genBinOp( | ... | @@ -7843,7 +7886,7 @@ fn genBinOp( |
| 7843 | }, | 7886 | }, |
| 7844 | else => unreachable, | 7887 | else => unreachable, |
| 7845 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ | 7888 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 7846 | @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?), | 7889 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 7847 | }), | 7890 | }), |
| 7848 | dst_reg, | 7891 | dst_reg, |
| 7849 | mask_reg, | 7892 | mask_reg, |
| ... | @@ -8645,6 +8688,9 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8645,6 +8688,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 8645 | else => unreachable, | 8688 | else => unreachable, |
| 8646 | }; | 8689 | }; |
| 8647 | | 8690 | |
| | 8691 | if (fn_info.is_var_args) |
| | 8692 | try self.asmRegisterImmediate(.{ ._, .mov }, .al, Immediate.u(call_info.fp_count)); |
| | 8693 | |
| 8648 | // Due to incremental compilation, how function calls are generated depends | 8694 | // Due to incremental compilation, how function calls are generated depends |
| 8649 | // on linking. | 8695 | // on linking. |
| 8650 | switch (info) { | 8696 | switch (info) { |
| ... | @@ -9240,8 +9286,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9240,8 +9286,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 9240 | } | 9286 | } |
| 9241 | | 9287 | |
| 9242 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 9288 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 9243 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; | | |
| 9244 | const mod = self.bin_file.options.module.?; | 9289 | const mod = self.bin_file.options.module.?; |
| | 9290 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 9245 | const func = mod.funcInfo(ty_fn.func); | 9291 | const func = mod.funcInfo(ty_fn.func); |
| 9246 | // TODO emit debug info for function change | 9292 | // TODO emit debug info for function change |
| 9247 | _ = func; | 9293 | _ = func; |
| ... | @@ -9868,9 +9914,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9868,9 +9914,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9868 | | 9914 | |
| 9869 | var outputs_extra_i = extra_i; | 9915 | var outputs_extra_i = extra_i; |
| 9870 | for (outputs) |output| { | 9916 | for (outputs) |output| { |
| 9871 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | 9917 | const extra_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 9872 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); | 9918 | const constraint = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 9873 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 9919 | const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 9874 | // This equation accounts for the fact that even if we have exactly 4 bytes | 9920 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 9875 | // for the string, we still use the next u32 for the null terminator. | 9921 | // for the string, we still use the next u32 for the null terminator. |
| 9876 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 9922 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | @@ -9915,16 +9961,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9915,16 +9961,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9915 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { | 9961 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 9916 | _ = self.register_manager.lockRegAssumeUnused(reg); | 9962 | _ = self.register_manager.lockRegAssumeUnused(reg); |
| 9917 | }; | 9963 | }; |
| 9918 | if (!std.mem.eql(u8, name, "_")) | 9964 | if (!mem.eql(u8, name, "_")) |
| 9919 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); | 9965 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| 9920 | args.appendAssumeCapacity(arg_mcv); | 9966 | args.appendAssumeCapacity(arg_mcv); |
| 9921 | if (output == .none) result = arg_mcv; | 9967 | if (output == .none) result = arg_mcv; |
| 9922 | } | 9968 | } |
| 9923 | | 9969 | |
| 9924 | for (inputs) |input| { | 9970 | for (inputs) |input| { |
| 9925 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | 9971 | const input_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 9926 | const constraint = std.mem.sliceTo(input_bytes, 0); | 9972 | const constraint = mem.sliceTo(input_bytes, 0); |
| 9927 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); | 9973 | const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 9928 | // This equation accounts for the fact that even if we have exactly 4 bytes | 9974 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 9929 | // for the string, we still use the next u32 for the null terminator. | 9975 | // for the string, we still use the next u32 for the null terminator. |
| 9930 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 9976 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | @@ -9975,7 +10021,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9975,7 +10021,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9975 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { | 10021 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 9976 | _ = self.register_manager.lockReg(reg); | 10022 | _ = self.register_manager.lockReg(reg); |
| 9977 | }; | 10023 | }; |
| 9978 | if (!std.mem.eql(u8, name, "_")) | 10024 | if (!mem.eql(u8, name, "_")) |
| 9979 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); | 10025 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| 9980 | args.appendAssumeCapacity(arg_mcv); | 10026 | args.appendAssumeCapacity(arg_mcv); |
| 9981 | } | 10027 | } |
| ... | @@ -9983,7 +10029,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9983,7 +10029,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9983 | { | 10029 | { |
| 9984 | var clobber_i: u32 = 0; | 10030 | var clobber_i: u32 = 0; |
| 9985 | while (clobber_i < clobbers_len) : (clobber_i += 1) { | 10031 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| 9986 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); | 10032 | const clobber = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 9987 | // This equation accounts for the fact that even if we have exactly 4 bytes | 10033 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 9988 | // for the string, we still use the next u32 for the null terminator. | 10034 | // for the string, we still use the next u32 for the null terminator. |
| 9989 | extra_i += clobber.len / 4 + 1; | 10035 | extra_i += clobber.len / 4 + 1; |
| ... | @@ -10050,26 +10096,26 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10050,26 +10096,26 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 10050 | arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse | 10096 | arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse |
| 10051 | return self.fail("no matching constraint: '{s}'", .{op_str}) | 10097 | return self.fail("no matching constraint: '{s}'", .{op_str}) |
| 10052 | ]) { | 10098 | ]) { |
| 10053 | .register => |reg| if (std.mem.eql(u8, modifier, "")) | 10099 | .register => |reg| if (mem.eql(u8, modifier, "")) |
| 10054 | .{ .reg = reg } | 10100 | .{ .reg = reg } |
| 10055 | else | 10101 | else |
| 10056 | return self.fail("invalid modifier: '{s}'", .{modifier}), | 10102 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 10057 | .memory => |addr| if (std.mem.eql(u8, modifier, "") or | 10103 | .memory => |addr| if (mem.eql(u8, modifier, "") or |
| 10058 | std.mem.eql(u8, modifier, "P")) | 10104 | mem.eql(u8, modifier, "P")) |
| 10059 | .{ .mem = Memory.sib( | 10105 | .{ .mem = Memory.sib( |
| 10060 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), | 10106 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), |
| 10061 | .{ .base = .{ .reg = .ds }, .disp = @intCast(@as(i64, @bitCast(addr))) }, | 10107 | .{ .base = .{ .reg = .ds }, .disp = @intCast(@as(i64, @bitCast(addr))) }, |
| 10062 | ) } | 10108 | ) } |
| 10063 | else | 10109 | else |
| 10064 | return self.fail("invalid modifier: '{s}'", .{modifier}), | 10110 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 10065 | .indirect => |reg_off| if (std.mem.eql(u8, modifier, "")) | 10111 | .indirect => |reg_off| if (mem.eql(u8, modifier, "")) |
| 10066 | .{ .mem = Memory.sib( | 10112 | .{ .mem = Memory.sib( |
| 10067 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), | 10113 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), |
| 10068 | .{ .base = .{ .reg = reg_off.reg }, .disp = reg_off.off }, | 10114 | .{ .base = .{ .reg = reg_off.reg }, .disp = reg_off.off }, |
| 10069 | ) } | 10115 | ) } |
| 10070 | else | 10116 | else |
| 10071 | return self.fail("invalid modifier: '{s}'", .{modifier}), | 10117 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 10072 | .load_frame => |frame_addr| if (std.mem.eql(u8, modifier, "")) | 10118 | .load_frame => |frame_addr| if (mem.eql(u8, modifier, "")) |
| 10073 | .{ .mem = Memory.sib( | 10119 | .{ .mem = Memory.sib( |
| 10074 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), | 10120 | mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}), |
| 10075 | .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }, | 10121 | .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }, |
| ... | @@ -10163,10 +10209,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10163,10 +10209,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 10163 | } | 10209 | } |
| 10164 | | 10210 | |
| 10165 | for (outputs, args.items[0..outputs.len]) |output, mcv| { | 10211 | for (outputs, args.items[0..outputs.len]) |output, mcv| { |
| 10166 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); | 10212 | const extra_bytes = mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); |
| 10167 | const constraint = | 10213 | const constraint = |
| 10168 | std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); | 10214 | mem.sliceTo(mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); |
| 10169 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 10215 | const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 10170 | // This equation accounts for the fact that even if we have exactly 4 bytes | 10216 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 10171 | // for the string, we still use the next u32 for the null terminator. | 10217 | // for the string, we still use the next u32 for the null terminator. |
| 10172 | outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 10218 | outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | @@ -10428,7 +10474,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -10428,7 +10474,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 10428 | else => {}, | 10474 | else => {}, |
| 10429 | }, | 10475 | }, |
| 10430 | } | 10476 | } |
| 10431 | return self.fail("TODO moveStrategy for {}", .{ty.fmt(self.bin_file.options.module.?)}); | 10477 | return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)}); |
| 10432 | } | 10478 | } |
| 10433 | | 10479 | |
| 10434 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { | 10480 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| ... | @@ -10626,9 +10672,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10626,9 +10672,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10626 | 80 => null, | 10672 | 80 => null, |
| 10627 | else => unreachable, | 10673 | else => unreachable, |
| 10628 | }, | 10674 | }, |
| 10629 | }) orelse return self.fail("TODO implement genSetReg for {}", .{ | 10675 | }) orelse return self.fail("TODO implement genSetReg for {}", .{ty.fmt(mod)}), |
| 10630 | ty.fmt(self.bin_file.options.module.?), | | |
| 10631 | }), | | |
| 10632 | registerAlias(dst_reg, abi_size), | 10676 | registerAlias(dst_reg, abi_size), |
| 10633 | registerAlias(src_reg, abi_size), | 10677 | registerAlias(src_reg, abi_size), |
| 10634 | ), | 10678 | ), |
| ... | @@ -11585,7 +11629,7 @@ fn atomicOp( | ... | @@ -11585,7 +11629,7 @@ fn atomicOp( |
| 11585 | try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem); | 11629 | try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem); |
| 11586 | }, | 11630 | }, |
| 11587 | else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{ | 11631 | else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{ |
| 11588 | val_ty.fmt(self.bin_file.options.module.?), @tagName(op), | 11632 | val_ty.fmt(mod), @tagName(op), |
| 11589 | }), | 11633 | }), |
| 11590 | }; | 11634 | }; |
| 11591 | try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem); | 11635 | try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem); |
| ... | @@ -12145,9 +12189,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -12145,9 +12189,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 12145 | else => unreachable, | 12189 | else => unreachable, |
| 12146 | }, | 12190 | }, |
| 12147 | } | 12191 | } |
| 12148 | return self.fail("TODO implement airSplat for {}", .{ | 12192 | return self.fail("TODO implement airSplat for {}", .{vector_ty.fmt(mod)}); |
| 12149 | vector_ty.fmt(self.bin_file.options.module.?), | | |
| 12150 | }); | | |
| 12151 | }; | 12193 | }; |
| 12152 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 12194 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 12153 | } | 12195 | } |
| ... | @@ -12373,9 +12415,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -12373,9 +12415,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 12373 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 12415 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 12374 | const ty = self.typeOfIndex(inst); | 12416 | const ty = self.typeOfIndex(inst); |
| 12375 | | 12417 | |
| 12376 | if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{ | 12418 | if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(mod)}); |
| 12377 | ty.fmt(self.bin_file.options.module.?), | | |
| 12378 | }); | | |
| 12379 | | 12419 | |
| 12380 | const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand }; | 12420 | const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand }; |
| 12381 | var mcvs: [3]MCValue = undefined; | 12421 | var mcvs: [3]MCValue = undefined; |
| ... | @@ -12491,9 +12531,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -12491,9 +12531,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 12491 | else => unreachable, | 12531 | else => unreachable, |
| 12492 | } | 12532 | } |
| 12493 | else | 12533 | else |
| 12494 | unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ | 12534 | unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(mod)}); |
| 12495 | ty.fmt(self.bin_file.options.module.?), | | |
| 12496 | }); | | |
| 12497 | | 12535 | |
| 12498 | var mops: [3]MCValue = undefined; | 12536 | var mops: [3]MCValue = undefined; |
| 12499 | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; | 12537 | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; |
| ... | @@ -12515,6 +12553,252 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -12515,6 +12553,252 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 12515 | return self.finishAir(inst, mops[0], ops); | 12553 | return self.finishAir(inst, mops[0], ops); |
| 12516 | } | 12554 | } |
| 12517 | | 12555 | |
| | 12556 | fn airVaStart(self: *Self, inst: Air.Inst.Index) !void { |
| | 12557 | const mod = self.bin_file.options.module.?; |
| | 12558 | const va_list_ty = self.air.instructions.items(.data)[inst].ty; |
| | 12559 | const ptr_anyopaque_ty = try mod.singleMutPtrType(Type.anyopaque); |
| | 12560 | |
| | 12561 | const result: MCValue = switch (abi.resolveCallingConvention( |
| | 12562 | self.fn_type.fnCallingConvention(mod), |
| | 12563 | self.target.*, |
| | 12564 | )) { |
| | 12565 | .SysV => result: { |
| | 12566 | const info = self.va_info.sysv; |
| | 12567 | const dst_fi = try self.allocFrameIndex(FrameAlloc.initType(va_list_ty, mod)); |
| | 12568 | var field_off: u31 = 0; |
| | 12569 | // gp_offset: c_uint, |
| | 12570 | try self.genSetMem( |
| | 12571 | .{ .frame = dst_fi }, |
| | 12572 | field_off, |
| | 12573 | Type.c_uint, |
| | 12574 | .{ .immediate = info.gp_count * 8 }, |
| | 12575 | ); |
| | 12576 | field_off += @intCast(Type.c_uint.abiSize(mod)); |
| | 12577 | // fp_offset: c_uint, |
| | 12578 | try self.genSetMem( |
| | 12579 | .{ .frame = dst_fi }, |
| | 12580 | field_off, |
| | 12581 | Type.c_uint, |
| | 12582 | .{ .immediate = abi.SysV.c_abi_int_param_regs.len * 8 + info.fp_count * 16 }, |
| | 12583 | ); |
| | 12584 | field_off += @intCast(Type.c_uint.abiSize(mod)); |
| | 12585 | // overflow_arg_area: *anyopaque, |
| | 12586 | try self.genSetMem( |
| | 12587 | .{ .frame = dst_fi }, |
| | 12588 | field_off, |
| | 12589 | ptr_anyopaque_ty, |
| | 12590 | .{ .lea_frame = info.overflow_arg_area }, |
| | 12591 | ); |
| | 12592 | field_off += @intCast(ptr_anyopaque_ty.abiSize(mod)); |
| | 12593 | // reg_save_area: *anyopaque, |
| | 12594 | try self.genSetMem( |
| | 12595 | .{ .frame = dst_fi }, |
| | 12596 | field_off, |
| | 12597 | ptr_anyopaque_ty, |
| | 12598 | .{ .lea_frame = info.reg_save_area }, |
| | 12599 | ); |
| | 12600 | field_off += @intCast(ptr_anyopaque_ty.abiSize(mod)); |
| | 12601 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| | 12602 | }, |
| | 12603 | .Win64 => return self.fail("TODO implement c_va_start for Win64", .{}), |
| | 12604 | else => unreachable, |
| | 12605 | }; |
| | 12606 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| | 12607 | } |
| | 12608 | |
| | 12609 | fn airVaArg(self: *Self, inst: Air.Inst.Index) !void { |
| | 12610 | const mod = self.bin_file.options.module.?; |
| | 12611 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 12612 | const ty = self.typeOfIndex(inst); |
| | 12613 | const promote_ty = self.promoteVarArg(ty); |
| | 12614 | const ptr_anyopaque_ty = try mod.singleMutPtrType(Type.anyopaque); |
| | 12615 | const unused = self.liveness.isUnused(inst); |
| | 12616 | |
| | 12617 | const result: MCValue = switch (abi.resolveCallingConvention( |
| | 12618 | self.fn_type.fnCallingConvention(mod), |
| | 12619 | self.target.*, |
| | 12620 | )) { |
| | 12621 | .SysV => result: { |
| | 12622 | try self.spillEflagsIfOccupied(); |
| | 12623 | |
| | 12624 | const tmp_regs = |
| | 12625 | try self.register_manager.allocRegs(2, .{ null, null }, abi.RegisterClass.gp); |
| | 12626 | const offset_reg = tmp_regs[0].to32(); |
| | 12627 | const addr_reg = tmp_regs[1].to64(); |
| | 12628 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
| | 12629 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| | 12630 | |
| | 12631 | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); |
| | 12632 | const promote_lock = switch (promote_mcv) { |
| | 12633 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 12634 | else => null, |
| | 12635 | }; |
| | 12636 | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); |
| | 12637 | |
| | 12638 | const ptr_arg_list_reg = |
| | 12639 | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); |
| | 12640 | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); |
| | 12641 | defer self.register_manager.unlockReg(ptr_arg_list_lock); |
| | 12642 | |
| | 12643 | const gp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 0 } }; |
| | 12644 | const fp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 4 } }; |
| | 12645 | const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } }; |
| | 12646 | const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } }; |
| | 12647 | |
| | 12648 | const classes = mem.sliceTo(&abi.classifySystemV(promote_ty, mod, .arg), .none); |
| | 12649 | switch (classes[0]) { |
| | 12650 | .integer => { |
| | 12651 | assert(classes.len == 1); |
| | 12652 | |
| | 12653 | try self.genSetReg(offset_reg, Type.c_uint, gp_offset); |
| | 12654 | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u( |
| | 12655 | abi.SysV.c_abi_int_param_regs.len * 8, |
| | 12656 | )); |
| | 12657 | const mem_reloc = try self.asmJccReloc(undefined, .ae); |
| | 12658 | |
| | 12659 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area); |
| | 12660 | if (!unused) |
| | 12661 | try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, Memory.sib(.qword, .{ |
| | 12662 | .base = .{ .reg = addr_reg }, |
| | 12663 | .scale_index = .{ .scale = 1, .index = offset_reg.to64() }, |
| | 12664 | })); |
| | 12665 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, Memory.sib(.qword, .{ |
| | 12666 | .base = .{ .reg = offset_reg.to64() }, |
| | 12667 | .disp = 8, |
| | 12668 | })); |
| | 12669 | try self.genCopy(Type.c_uint, gp_offset, .{ .register = offset_reg }); |
| | 12670 | const done_reloc = try self.asmJmpReloc(undefined); |
| | 12671 | |
| | 12672 | try self.performReloc(mem_reloc); |
| | 12673 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area); |
| | 12674 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), Memory.sib(.qword, .{ |
| | 12675 | .base = .{ .reg = addr_reg }, |
| | 12676 | .disp = @intCast(@max(promote_ty.abiSize(mod), 8)), |
| | 12677 | })); |
| | 12678 | try self.genCopy( |
| | 12679 | ptr_anyopaque_ty, |
| | 12680 | overflow_arg_area, |
| | 12681 | .{ .register = offset_reg.to64() }, |
| | 12682 | ); |
| | 12683 | |
| | 12684 | try self.performReloc(done_reloc); |
| | 12685 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| | 12686 | .indirect = .{ .reg = addr_reg }, |
| | 12687 | }); |
| | 12688 | }, |
| | 12689 | .sse => { |
| | 12690 | assert(classes.len == 1); |
| | 12691 | |
| | 12692 | try self.genSetReg(offset_reg, Type.c_uint, fp_offset); |
| | 12693 | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u( |
| | 12694 | abi.SysV.c_abi_int_param_regs.len * 8 + abi.SysV.c_abi_sse_param_regs.len * 16, |
| | 12695 | )); |
| | 12696 | const mem_reloc = try self.asmJccReloc(undefined, .ae); |
| | 12697 | |
| | 12698 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area); |
| | 12699 | if (!unused) |
| | 12700 | try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, Memory.sib(.qword, .{ |
| | 12701 | .base = .{ .reg = addr_reg }, |
| | 12702 | .scale_index = .{ .scale = 1, .index = offset_reg.to64() }, |
| | 12703 | })); |
| | 12704 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, Memory.sib(.qword, .{ |
| | 12705 | .base = .{ .reg = offset_reg.to64() }, |
| | 12706 | .disp = 16, |
| | 12707 | })); |
| | 12708 | try self.genCopy(Type.c_uint, fp_offset, .{ .register = offset_reg }); |
| | 12709 | const done_reloc = try self.asmJmpReloc(undefined); |
| | 12710 | |
| | 12711 | try self.performReloc(mem_reloc); |
| | 12712 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area); |
| | 12713 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), Memory.sib(.qword, .{ |
| | 12714 | .base = .{ .reg = addr_reg }, |
| | 12715 | .disp = @intCast(@max(promote_ty.abiSize(mod), 8)), |
| | 12716 | })); |
| | 12717 | try self.genCopy( |
| | 12718 | ptr_anyopaque_ty, |
| | 12719 | overflow_arg_area, |
| | 12720 | .{ .register = offset_reg.to64() }, |
| | 12721 | ); |
| | 12722 | |
| | 12723 | try self.performReloc(done_reloc); |
| | 12724 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| | 12725 | .indirect = .{ .reg = addr_reg }, |
| | 12726 | }); |
| | 12727 | }, |
| | 12728 | .memory => { |
| | 12729 | assert(classes.len == 1); |
| | 12730 | unreachable; |
| | 12731 | }, |
| | 12732 | else => return self.fail("TODO implement c_va_arg for {} on SysV", .{ |
| | 12733 | promote_ty.fmt(mod), |
| | 12734 | }), |
| | 12735 | } |
| | 12736 | |
| | 12737 | if (unused) break :result .unreach; |
| | 12738 | if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv; |
| | 12739 | |
| | 12740 | if (!promote_ty.isRuntimeFloat()) { |
| | 12741 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 12742 | try self.genCopy(ty, dst_mcv, promote_mcv); |
| | 12743 | break :result dst_mcv; |
| | 12744 | } |
| | 12745 | |
| | 12746 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); |
| | 12747 | const dst_mcv = if (promote_mcv.isRegister()) |
| | 12748 | promote_mcv |
| | 12749 | else |
| | 12750 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); |
| | 12751 | const dst_reg = dst_mcv.getReg().?.to128(); |
| | 12752 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| | 12753 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| | 12754 | |
| | 12755 | if (self.hasFeature(.avx)) if (promote_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| | 12756 | .{ .v_ss, .cvtsd2 }, |
| | 12757 | dst_reg, |
| | 12758 | dst_reg, |
| | 12759 | promote_mcv.mem(.qword), |
| | 12760 | ) else try self.asmRegisterRegisterRegister( |
| | 12761 | .{ .v_ss, .cvtsd2 }, |
| | 12762 | dst_reg, |
| | 12763 | dst_reg, |
| | 12764 | (if (promote_mcv.isRegister()) |
| | 12765 | promote_mcv.getReg().? |
| | 12766 | else |
| | 12767 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| | 12768 | ) else if (promote_mcv.isMemory()) try self.asmRegisterMemory( |
| | 12769 | .{ ._ss, .cvtsd2 }, |
| | 12770 | dst_reg, |
| | 12771 | promote_mcv.mem(.qword), |
| | 12772 | ) else try self.asmRegisterRegister( |
| | 12773 | .{ ._ss, .cvtsd2 }, |
| | 12774 | dst_reg, |
| | 12775 | (if (promote_mcv.isRegister()) |
| | 12776 | promote_mcv.getReg().? |
| | 12777 | else |
| | 12778 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| | 12779 | ); |
| | 12780 | break :result promote_mcv; |
| | 12781 | }, |
| | 12782 | .Win64 => return self.fail("TODO implement c_va_arg for Win64", .{}), |
| | 12783 | else => unreachable, |
| | 12784 | }; |
| | 12785 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 12786 | } |
| | 12787 | |
| | 12788 | fn airVaCopy(self: *Self, inst: Air.Inst.Index) !void { |
| | 12789 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 12790 | const ptr_va_list_ty = self.typeOf(ty_op.operand); |
| | 12791 | |
| | 12792 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 12793 | try self.load(dst_mcv, ptr_va_list_ty, .{ .air_ref = ty_op.operand }); |
| | 12794 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| | 12795 | } |
| | 12796 | |
| | 12797 | fn airVaEnd(self: *Self, inst: Air.Inst.Index) !void { |
| | 12798 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 12799 | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| | 12800 | } |
| | 12801 | |
| 12518 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | 12802 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 12519 | const mod = self.bin_file.options.module.?; | 12803 | const mod = self.bin_file.options.module.?; |
| 12520 | const ty = self.typeOf(ref); | 12804 | const ty = self.typeOf(ref); |
| ... | @@ -12593,6 +12877,8 @@ const CallMCValues = struct { | ... | @@ -12593,6 +12877,8 @@ const CallMCValues = struct { |
| 12593 | return_value: InstTracking, | 12877 | return_value: InstTracking, |
| 12594 | stack_byte_count: u31, | 12878 | stack_byte_count: u31, |
| 12595 | stack_align: Alignment, | 12879 | stack_align: Alignment, |
| | 12880 | gp_count: u32, |
| | 12881 | fp_count: u32, |
| 12596 | | 12882 | |
| 12597 | fn deinit(self: *CallMCValues, func: *Self) void { | 12883 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 12598 | func.gpa.free(self.args); | 12884 | func.gpa.free(self.args); |
| ... | @@ -12616,8 +12902,8 @@ fn resolveCallingConventionValues( | ... | @@ -12616,8 +12902,8 @@ fn resolveCallingConventionValues( |
| 12616 | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { | 12902 | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { |
| 12617 | dest.* = src.toType(); | 12903 | dest.* = src.toType(); |
| 12618 | } | 12904 | } |
| 12619 | // TODO: promote var arg types | 12905 | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| |
| 12620 | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| param_ty.* = arg_ty; | 12906 | param_ty.* = self.promoteVarArg(arg_ty); |
| 12621 | | 12907 | |
| 12622 | var result: CallMCValues = .{ | 12908 | var result: CallMCValues = .{ |
| 12623 | .args = try self.gpa.alloc(MCValue, param_types.len), | 12909 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| ... | @@ -12625,6 +12911,8 @@ fn resolveCallingConventionValues( | ... | @@ -12625,6 +12911,8 @@ fn resolveCallingConventionValues( |
| 12625 | .return_value = undefined, | 12911 | .return_value = undefined, |
| 12626 | .stack_byte_count = 0, | 12912 | .stack_byte_count = 0, |
| 12627 | .stack_align = undefined, | 12913 | .stack_align = undefined, |
| | 12914 | .gp_count = 0, |
| | 12915 | .fp_count = 0, |
| 12628 | }; | 12916 | }; |
| 12629 | errdefer self.gpa.free(result.args); | 12917 | errdefer self.gpa.free(result.args); |
| 12630 | | 12918 | |
| ... | @@ -12638,10 +12926,10 @@ fn resolveCallingConventionValues( | ... | @@ -12638,10 +12926,10 @@ fn resolveCallingConventionValues( |
| 12638 | result.stack_align = .@"8"; | 12926 | result.stack_align = .@"8"; |
| 12639 | }, | 12927 | }, |
| 12640 | .C, .SysV, .Win64 => { | 12928 | .C, .SysV, .Win64 => { |
| 12641 | var ret_int_reg_i: usize = 0; | 12929 | var ret_int_reg_i: u32 = 0; |
| 12642 | var ret_sse_reg_i: usize = 0; | 12930 | var ret_sse_reg_i: u32 = 0; |
| 12643 | var param_int_reg_i: usize = 0; | 12931 | var param_int_reg_i: u32 = 0; |
| 12644 | var param_sse_reg_i: usize = 0; | 12932 | var param_sse_reg_i: u32 = 0; |
| 12645 | result.stack_align = .@"16"; | 12933 | result.stack_align = .@"16"; |
| 12646 | | 12934 | |
| 12647 | switch (resolved_cc) { | 12935 | switch (resolved_cc) { |
| ... | @@ -12800,6 +13088,10 @@ fn resolveCallingConventionValues( | ... | @@ -12800,6 +13088,10 @@ fn resolveCallingConventionValues( |
| 12800 | } }; | 13088 | } }; |
| 12801 | result.stack_byte_count += param_size; | 13089 | result.stack_byte_count += param_size; |
| 12802 | } | 13090 | } |
| | 13091 | assert(param_int_reg_i <= 6); |
| | 13092 | result.gp_count = param_int_reg_i; |
| | 13093 | assert(param_sse_reg_i <= 16); |
| | 13094 | result.fp_count = param_sse_reg_i; |
| 12803 | }, | 13095 | }, |
| 12804 | .Unspecified => { | 13096 | .Unspecified => { |
| 12805 | result.stack_align = .@"16"; | 13097 | result.stack_align = .@"16"; |
| ... | @@ -13051,3 +13343,35 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 { | ... | @@ -13051,3 +13343,35 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 { |
| 13051 | else => unreachable, | 13343 | else => unreachable, |
| 13052 | }; | 13344 | }; |
| 13053 | } | 13345 | } |
| | 13346 | |
| | 13347 | fn promoteVarArg(self: *Self, ty: Type) Type { |
| | 13348 | const mod = self.bin_file.options.module.?; |
| | 13349 | switch (ty.zigTypeTag(mod)) { |
| | 13350 | .Bool => return Type.c_int, |
| | 13351 | else => { |
| | 13352 | const int_info = ty.intInfo(mod); |
| | 13353 | for ([_]Type{ |
| | 13354 | Type.c_int, Type.c_uint, |
| | 13355 | Type.c_long, Type.c_ulong, |
| | 13356 | Type.c_longlong, Type.c_ulonglong, |
| | 13357 | }) |promote_ty| { |
| | 13358 | const promote_info = promote_ty.intInfo(mod); |
| | 13359 | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| | 13360 | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| | 13361 | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| | 13362 | } |
| | 13363 | unreachable; |
| | 13364 | }, |
| | 13365 | .Float => switch (ty.floatBits(self.target.*)) { |
| | 13366 | 32, 64 => return Type.f64, |
| | 13367 | else => |float_bits| { |
| | 13368 | assert(float_bits == self.target.c_type_bit_size(.longdouble)); |
| | 13369 | return Type.c_longdouble; |
| | 13370 | }, |
| | 13371 | }, |
| | 13372 | .Pointer => { |
| | 13373 | assert(!ty.isSlice(mod)); |
| | 13374 | return ty; |
| | 13375 | }, |
| | 13376 | } |
| | 13377 | } |