| ... | ... | @@ -2050,7 +2050,16 @@ fn gen( |
| 2050 | 2050 | |
| 2051 | 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 | 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 | 176029 | .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null), |
| 176021 | 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 | 176033 | switch (dst_arg) { |
| 176025 | 176034 | .none => {}, |
| 176026 | 176035 | .register => |reg| { |
| 176027 | 176036 | try self.register_manager.getReg(reg, null); |
| 176028 | 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 | 176049 | .register_pair => |regs| { |
| 176031 | 176050 | for (regs) |reg| try self.register_manager.getReg(reg, null); |
| ... | ... | @@ -176129,7 +176148,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176129 | 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 | 176152 | switch (dst_arg) { |
| 176134 | 176153 | .none, .load_frame => {}, |
| 176135 | 176154 | .register => |dst_reg| switch (fn_info.cc) { |
| ... | ... | @@ -176144,6 +176163,16 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176144 | 176163 | try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); |
| 176145 | 176164 | if (promoted_ty.toIntern() != arg_ty.toIntern()) |
| 176146 | 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 | 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 | 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 | 176215 | // Due to incremental compilation, how function calls are generated depends |
| 176186 | 176216 | // on linking. |
| ... | ... | @@ -180782,7 +180812,18 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180782 | 180812 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 180783 | 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 | 180827 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180787 | 180828 | }; |
| 180788 | 180829 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| ... | ... | @@ -180921,48 +180962,103 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180921 | 180962 | break :result dst_mcv; |
| 180922 | 180963 | } |
| 180923 | 180964 | |
| 180924 | | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); |
| 180925 | | const dst_mcv = if (promote_mcv.isRegister()) |
| 180926 | | promote_mcv |
| 180927 | | else |
| 180928 | | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); |
| 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); |
| 180965 | try self.convertFloatVarArg(inst, ty, promote_ty, promote_mcv); |
| 180966 | break :result promote_mcv; |
| 180967 | }, |
| 180968 | .x86_64_win => result: { |
| 180969 | try self.spillEflagsIfOccupied(); |
| 180932 | 180970 | |
| 180933 | | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 180934 | | .{ .v_ss, .cvtsd2 }, |
| 180935 | | dst_reg, |
| 180936 | | dst_reg, |
| 180937 | | try promote_mcv.mem(self, .{ .size = .qword }), |
| 180938 | | ) else try self.asmRegisterRegisterRegister( |
| 180939 | | .{ .v_ss, .cvtsd2 }, |
| 180940 | | dst_reg, |
| 180941 | | dst_reg, |
| 180942 | | (if (promote_mcv.isRegister()) |
| 180943 | | promote_mcv.getReg().? |
| 180944 | | else |
| 180945 | | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 180946 | | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( |
| 180947 | | .{ ._ss, .cvtsd2 }, |
| 180948 | | dst_reg, |
| 180949 | | try promote_mcv.mem(self, .{ .size = .qword }), |
| 180950 | | ) else try self.asmRegisterRegister( |
| 180951 | | .{ ._ss, .cvtsd2 }, |
| 180952 | | dst_reg, |
| 180953 | | (if (promote_mcv.isRegister()) |
| 180954 | | promote_mcv.getReg().? |
| 180955 | | else |
| 180956 | | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 180957 | | ); |
| 180971 | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); |
| 180972 | const promote_lock = switch (promote_mcv) { |
| 180973 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 180974 | else => null, |
| 180975 | }; |
| 180976 | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); |
| 180977 | |
| 180978 | const ptr_arg_list_reg = |
| 180979 | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); |
| 180980 | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); |
| 180981 | defer self.register_manager.unlockReg(ptr_arg_list_lock); |
| 180982 | |
| 180983 | const next_arg_ptr: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg } }; |
| 180984 | |
| 180985 | const class = abi.classifyWindows(promote_ty, zcu, self.target, .arg); |
| 180986 | switch (class) { |
| 180987 | .integer, .sse => { |
| 180988 | const next_arg_ptr_reg = try self.copyToTmpRegister(.usize, next_arg_ptr); |
| 180989 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 180990 | .indirect = .{ .reg = next_arg_ptr_reg }, |
| 180991 | }, .{}); |
| 180992 | try self.asmRegisterMemory(.{ ._, .lea }, next_arg_ptr_reg, .{ |
| 180993 | .base = .{ .reg = next_arg_ptr_reg.to64() }, |
| 180994 | .mod = .{ .rm = .{ .disp = 8 } }, |
| 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 | 181012 | break :result promote_mcv; |
| 180959 | 181013 | }, |
| 180960 | | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), |
| 180961 | 181014 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180962 | 181015 | }; |
| 180963 | 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 | 181062 | fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180967 | 181063 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 180968 | 181064 | const ptr_va_list_ty = self.typeOf(ty_op.operand); |