| ... | @@ -2050,7 +2050,16 @@ fn gen( | ... | @@ -2050,7 +2050,16 @@ fn gen( |
| 2050 | | 2050 | |
| 2051 | self.performReloc(skip_sse_reloc); | 2051 | self.performReloc(skip_sse_reloc); |
| 2052 | }, | 2052 | }, |
| 2053 | .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}), | 2053 | .x86_64_win => { |
| | 2054 | for (abi.Win64.c_abi_int_param_regs[0..], 0..) |reg, reg_i| |
| | 2055 | try self.genSetMem( |
| | 2056 | .{ .frame = .args_frame }, |
| | 2057 | @intCast(reg_i * 8), |
| | 2058 | .usize, |
| | 2059 | .{ .register = reg }, |
| | 2060 | .{}, |
| | 2061 | ); |
| | 2062 | }, |
| 2054 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), | 2063 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 2055 | }; | 2064 | }; |
| 2056 | | 2065 | |
| ... | @@ -176020,12 +176029,22 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -176020,12 +176029,22 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176020 | .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null), | 176029 | .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null), |
| 176021 | else => unreachable, | 176030 | else => unreachable, |
| 176022 | } | 176031 | } |
| 176023 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index| | 176032 | for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, *frame_index, arg_i| |
| 176024 | switch (dst_arg) { | 176033 | switch (dst_arg) { |
| 176025 | .none => {}, | 176034 | .none => {}, |
| 176026 | .register => |reg| { | 176035 | .register => |reg| { |
| 176027 | try self.register_manager.getReg(reg, null); | 176036 | try self.register_manager.getReg(reg, null); |
| 176028 | try reg_locks.append(self.register_manager.lockReg(reg)); | 176037 | try reg_locks.append(self.register_manager.lockReg(reg)); |
| | 176038 | |
| | 176039 | if (fn_info.is_var_args and |
| | 176040 | fn_info.cc == .x86_64_win and |
| | 176041 | reg.class() == .sse and |
| | 176042 | arg_i < abi.Win64.c_abi_int_param_regs.len) |
| | 176043 | { |
| | 176044 | // Floating point arguments must be duplicated into the equivalent integer registers on this ABI |
| | 176045 | const int_reg = abi.Win64.c_abi_int_param_regs[arg_i]; |
| | 176046 | try reg_locks.append(self.register_manager.lockReg(int_reg)); |
| | 176047 | } |
| 176029 | }, | 176048 | }, |
| 176030 | .register_pair => |regs| { | 176049 | .register_pair => |regs| { |
| 176031 | for (regs) |reg| try self.register_manager.getReg(reg, null); | 176050 | for (regs) |reg| try self.register_manager.getReg(reg, null); |
| ... | @@ -176129,7 +176148,7 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -176129,7 +176148,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176129 | else => unreachable, | 176148 | else => unreachable, |
| 176130 | } | 176149 | } |
| 176131 | | 176150 | |
| 176132 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| | 176151 | for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, frame_index, arg_i| |
| 176133 | switch (dst_arg) { | 176152 | switch (dst_arg) { |
| 176134 | .none, .load_frame => {}, | 176153 | .none, .load_frame => {}, |
| 176135 | .register => |dst_reg| switch (fn_info.cc) { | 176154 | .register => |dst_reg| switch (fn_info.cc) { |
| ... | @@ -176144,6 +176163,16 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -176144,6 +176163,16 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176144 | try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); | 176163 | try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); |
| 176145 | if (promoted_ty.toIntern() != arg_ty.toIntern()) | 176164 | if (promoted_ty.toIntern() != arg_ty.toIntern()) |
| 176146 | try self.truncateRegister(arg_ty, dst_alias); | 176165 | try self.truncateRegister(arg_ty, dst_alias); |
| | 176166 | |
| | 176167 | if (fn_info.is_var_args and |
| | 176168 | fn_info.cc == .x86_64_win and |
| | 176169 | dst_reg.class() == .sse and |
| | 176170 | arg_i < abi.Win64.c_abi_int_param_regs.len) |
| | 176171 | { |
| | 176172 | const int_dst_reg = abi.Win64.c_abi_int_param_regs[arg_i]; |
| | 176173 | const int_dst_alias = registerAlias(int_dst_reg, promoted_abi_size); |
| | 176174 | try self.genSetReg(int_dst_alias, promoted_ty, .{ .register = dst_alias }, opts); |
| | 176175 | } |
| 176147 | }, | 176176 | }, |
| 176148 | }, | 176177 | }, |
| 176149 | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts), | 176178 | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts), |
| ... | @@ -176180,7 +176209,8 @@ fn genCall(self: *CodeGen, info: union(enum) { | ... | @@ -176180,7 +176209,8 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176180 | else => unreachable, | 176209 | else => unreachable, |
| 176181 | }; | 176210 | }; |
| 176182 | | 176211 | |
| 176183 | if (fn_info.is_var_args) try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); | 176212 | if (fn_info.is_var_args and fn_info.cc == .x86_64_sysv) |
| | 176213 | try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); |
| 176184 | | 176214 | |
| 176185 | // Due to incremental compilation, how function calls are generated depends | 176215 | // Due to incremental compilation, how function calls are generated depends |
| 176186 | // on linking. | 176216 | // on linking. |
| ... | @@ -180782,7 +180812,18 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -180782,7 +180812,18 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180782 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); | 180812 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 180783 | break :result .{ .load_frame = .{ .index = dst_fi } }; | 180813 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| 180784 | }, | 180814 | }, |
| 180785 | .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}), | 180815 | .x86_64_win => result: { |
| | 180816 | const dst_fi = try self.allocFrameIndex(.initSpill(va_list_ty, zcu)); |
| | 180817 | const fn_info = zcu.typeToFunc(self.fn_type).?; |
| | 180818 | try self.genSetMem( |
| | 180819 | .{ .frame = dst_fi }, |
| | 180820 | 0, |
| | 180821 | ptr_anyopaque_ty, |
| | 180822 | .{ .lea_frame = .{ .index = .args_frame, .off = @intCast(fn_info.param_types.len * 8) } }, |
| | 180823 | .{}, |
| | 180824 | ); |
| | 180825 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| | 180826 | }, |
| 180786 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), | 180827 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180787 | }; | 180828 | }; |
| 180788 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 180829 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| ... | @@ -180921,48 +180962,103 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -180921,48 +180962,103 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180921 | break :result dst_mcv; | 180962 | break :result dst_mcv; |
| 180922 | } | 180963 | } |
| 180923 | | 180964 | |
| 180924 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); | 180965 | try self.convertFloatVarArg(inst, ty, promote_ty, promote_mcv); |
| 180925 | const dst_mcv = if (promote_mcv.isRegister()) | 180966 | break :result promote_mcv; |
| 180926 | promote_mcv | 180967 | }, |
| 180927 | else | 180968 | .x86_64_win => result: { |
| 180928 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); | 180969 | try self.spillEflagsIfOccupied(); |
| 180929 | const dst_reg = dst_mcv.getReg().?.to128(); | | |
| 180930 | const dst_lock = self.register_manager.lockReg(dst_reg); | | |
| 180931 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 180932 | | 180970 | |
| 180933 | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( | 180971 | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); |
| 180934 | .{ .v_ss, .cvtsd2 }, | 180972 | const promote_lock = switch (promote_mcv) { |
| 180935 | dst_reg, | 180973 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 180936 | dst_reg, | 180974 | else => null, |
| 180937 | try promote_mcv.mem(self, .{ .size = .qword }), | 180975 | }; |
| 180938 | ) else try self.asmRegisterRegisterRegister( | 180976 | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); |
| 180939 | .{ .v_ss, .cvtsd2 }, | 180977 | |
| 180940 | dst_reg, | 180978 | const ptr_arg_list_reg = |
| 180941 | dst_reg, | 180979 | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); |
| 180942 | (if (promote_mcv.isRegister()) | 180980 | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); |
| 180943 | promote_mcv.getReg().? | 180981 | defer self.register_manager.unlockReg(ptr_arg_list_lock); |
| 180944 | else | 180982 | |
| 180945 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | 180983 | const next_arg_ptr: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg } }; |
| 180946 | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( | 180984 | |
| 180947 | .{ ._ss, .cvtsd2 }, | 180985 | const class = abi.classifyWindows(promote_ty, zcu, self.target, .arg); |
| 180948 | dst_reg, | 180986 | switch (class) { |
| 180949 | try promote_mcv.mem(self, .{ .size = .qword }), | 180987 | .integer, .sse => { |
| 180950 | ) else try self.asmRegisterRegister( | 180988 | const next_arg_ptr_reg = try self.copyToTmpRegister(.usize, next_arg_ptr); |
| 180951 | .{ ._ss, .cvtsd2 }, | 180989 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 180952 | dst_reg, | 180990 | .indirect = .{ .reg = next_arg_ptr_reg }, |
| 180953 | (if (promote_mcv.isRegister()) | 180991 | }, .{}); |
| 180954 | promote_mcv.getReg().? | 180992 | try self.asmRegisterMemory(.{ ._, .lea }, next_arg_ptr_reg, .{ |
| 180955 | else | 180993 | .base = .{ .reg = next_arg_ptr_reg.to64() }, |
| 180956 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | 180994 | .mod = .{ .rm = .{ .disp = 8 } }, |
| 180957 | ); | 180995 | }); |
| | 180996 | try self.genCopy(.usize, next_arg_ptr, .{ .register = next_arg_ptr_reg }, .{}); |
| | 180997 | }, |
| | 180998 | .memory => unreachable, |
| | 180999 | else => return self.fail("TODO implement c_va_arg for {f} on Win64", .{promote_ty.fmt(pt)}), |
| | 181000 | } |
| | 181001 | |
| | 181002 | if (unused) break :result .unreach; |
| | 181003 | if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv; |
| | 181004 | |
| | 181005 | if (!promote_ty.isRuntimeFloat()) { |
| | 181006 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 181007 | try self.genCopy(ty, dst_mcv, promote_mcv, .{}); |
| | 181008 | break :result dst_mcv; |
| | 181009 | } |
| | 181010 | |
| | 181011 | try self.convertFloatVarArg(inst, ty, promote_ty, promote_mcv); |
| 180958 | break :result promote_mcv; | 181012 | break :result promote_mcv; |
| 180959 | }, | 181013 | }, |
| 180960 | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), | | |
| 180961 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), | 181014 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180962 | }; | 181015 | }; |
| 180963 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 181016 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 180964 | } | 181017 | } |
| 180965 | | 181018 | |
| | 181019 | fn convertFloatVarArg( |
| | 181020 | self: *CodeGen, |
| | 181021 | inst: Air.Inst.Index, |
| | 181022 | ty: Type, |
| | 181023 | promote_ty: Type, |
| | 181024 | promote_mcv: MCValue, |
| | 181025 | ) !void { |
| | 181026 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); |
| | 181027 | const dst_mcv = if (promote_mcv.isRegister()) |
| | 181028 | promote_mcv |
| | 181029 | else |
| | 181030 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); |
| | 181031 | const dst_reg = dst_mcv.getReg().?.to128(); |
| | 181032 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| | 181033 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| | 181034 | |
| | 181035 | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| | 181036 | .{ .v_ss, .cvtsd2 }, |
| | 181037 | dst_reg, |
| | 181038 | dst_reg, |
| | 181039 | try promote_mcv.mem(self, .{ .size = .qword }), |
| | 181040 | ) else try self.asmRegisterRegisterRegister( |
| | 181041 | .{ .v_ss, .cvtsd2 }, |
| | 181042 | dst_reg, |
| | 181043 | dst_reg, |
| | 181044 | (if (promote_mcv.isRegister()) |
| | 181045 | promote_mcv.getReg().? |
| | 181046 | else |
| | 181047 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| | 181048 | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( |
| | 181049 | .{ ._ss, .cvtsd2 }, |
| | 181050 | dst_reg, |
| | 181051 | try promote_mcv.mem(self, .{ .size = .qword }), |
| | 181052 | ) else try self.asmRegisterRegister( |
| | 181053 | .{ ._ss, .cvtsd2 }, |
| | 181054 | dst_reg, |
| | 181055 | (if (promote_mcv.isRegister()) |
| | 181056 | promote_mcv.getReg().? |
| | 181057 | else |
| | 181058 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| | 181059 | ); |
| | 181060 | } |
| | 181061 | |
| 180966 | fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void { | 181062 | fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180967 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 181063 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 180968 | const ptr_va_list_ty = self.typeOf(ty_op.operand); | 181064 | const ptr_va_list_ty = self.typeOf(ty_op.operand); |