authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-07 00:39:24-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-07 02:10:34-04:00
log7436f3efc9fd3337431dce16ca12393819394dc1
tree79c42b6ec82749cd7cf686fecdd42363a987cc3e
parent20b4401cdef1baa377276ecae31f266cf85d4d2e

x86_64: implement C var args


3 files changed, 413 insertions(+), 96 deletions(-)

src/arch/x86_64/CodeGen.zig+411-87
...@@ -58,6 +58,15 @@ target: *const std.Target,...@@ -58,6 +58,15 @@ target: *const std.Target,
58owner: Owner,58owner: Owner,
59err_msg: ?*ErrorMsg,59err_msg: ?*ErrorMsg,
60args: []MCValue,60args: []MCValue,
61va_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},
61ret_mcv: InstTracking,70ret_mcv: InstTracking,
62fn_type: Type,71fn_type: Type,
63arg_index: u32,72arg_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 );
786796
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 };
822843
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(
16601682
1661fn gen(self: *Self) InnerError!void {1683fn 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 }
16921715
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);
16941753
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", .{}),
20662125
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),
20712130
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)});
21092168
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 });
29202977
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 }
45744631
...@@ -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 }
47034760
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.?)});
47064762
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 });
52485299
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);
55985649
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 });
56025651
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}
58085855
...@@ -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 }
61146160
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:
6170fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {6216fn 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 },
69817024
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 });
75727615
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 };
86478690
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 depends8694 // 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}
92419287
9242fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {9288fn 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 change9292 // 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 {
98689914
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 bytes9920 // 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 }
99239969
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 bytes9974 // 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 bytes10033 // 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]) orelse10096 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 else10101 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, "") or10103 .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 else10109 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 else10116 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 }
1016410210
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 bytes10216 // 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}
1043310479
10434fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {10480fn 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);
1237512417
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 });
1237912419
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 else12533 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 });
1249712535
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}
1251712555
12556fn 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
12609fn 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
12788fn 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
12797fn 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
12518fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {12802fn 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,
1259612882
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 types12905 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);
1262112907
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);
1263012918
...@@ -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";
1264612934
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
13347fn 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}
test/behavior/var_args.zig-4
...@@ -108,7 +108,6 @@ test "simple variadic function" {...@@ -108,7 +108,6 @@ test "simple variadic function" {
108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
111 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;111 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
113 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {112 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
114 // https://github.com/ziglang/zig/issues/14096113 // https://github.com/ziglang/zig/issues/14096
...@@ -158,7 +157,6 @@ test "variadic functions" {...@@ -158,7 +157,6 @@ test "variadic functions" {
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;160 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
163 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {161 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
164 // https://github.com/ziglang/zig/issues/14096162 // https://github.com/ziglang/zig/issues/14096
...@@ -202,7 +200,6 @@ test "copy VaList" {...@@ -202,7 +200,6 @@ test "copy VaList" {
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;203 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
207 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {204 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
208 // https://github.com/ziglang/zig/issues/14096205 // https://github.com/ziglang/zig/issues/14096
...@@ -235,7 +232,6 @@ test "unused VaList arg" {...@@ -235,7 +232,6 @@ test "unused VaList arg" {
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
237 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO234 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
238 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;235 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
240 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {236 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
241 // https://github.com/ziglang/zig/issues/14096237 // https://github.com/ziglang/zig/issues/14096
test/behavior/widening.zig+2-5
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const mem = std.mem;3const mem = std.mem;
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
65
7test "integer widening" {6test "integer widening" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -53,10 +52,8 @@ test "float widening" {...@@ -53,10 +52,8 @@ test "float widening" {
53 try expect(a == b);52 try expect(a == b);
54 try expect(b == c);53 try expect(b == c);
55 try expect(c == d);54 try expect(c == d);
56 if (has_f80_rt) {55 var e: f80 = c;
57 var e: f80 = c;56 try expect(c == e);
58 try expect(c == e);
59 }
60}57}
6158
62test "float widening f16 to f128" {59test "float widening f16 to f128" {