authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-06-19 19:31:25-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-06-20 21:08:23-04:00
log2e7bd58abaafae8a029bc1a372085ace6738a365
tree7392236a43c7daef8664814d926d482f67fef0cd
parentfba5c230f043a14e5b73c25add54cd1f2b15ba40

x86_64: fix incorrect lowering of win64 varargs


4 files changed, 608 insertions(+), 528 deletions(-)

src/codegen/x86_64/CodeGen.zig+542-512
...@@ -211,10 +211,10 @@ pub const MCValue = union(enum) {...@@ -211,10 +211,10 @@ pub const MCValue = union(enum) {
211 /// The value is in memory at a constant offset from the address in a register.211 /// The value is in memory at a constant offset from the address in a register.
212 indirect: bits.RegisterOffset,212 indirect: bits.RegisterOffset,
213 indirect_load_frame: bits.FrameAddr,213 indirect_load_frame: bits.FrameAddr,
214 /// The value stored at an offset from a frame index214 /// The value stored at an offset from a frame index.
215 /// Payload is a frame address.215 /// Payload is a frame address.
216 load_frame: bits.FrameAddr,216 load_frame: bits.FrameAddr,
217 /// The address of an offset from a frame index217 /// The address of an offset from a frame index.
218 /// Payload is a frame address.218 /// Payload is a frame address.
219 lea_frame: bits.FrameAddr,219 lea_frame: bits.FrameAddr,
220 load_nav: InternPool.Nav.Index,220 load_nav: InternPool.Nav.Index,
...@@ -225,15 +225,17 @@ pub const MCValue = union(enum) {...@@ -225,15 +225,17 @@ pub const MCValue = union(enum) {
225 lea_lazy_sym: link.File.LazySymbol,225 lea_lazy_sym: link.File.LazySymbol,
226 load_extern_func: Mir.NullTerminatedString,226 load_extern_func: Mir.NullTerminatedString,
227 lea_extern_func: Mir.NullTerminatedString,227 lea_extern_func: Mir.NullTerminatedString,
228 /// Supports `integer_per_element` abi228 /// The value is duplicated in two different registers.
229 register_tee: [4]Register,
230 /// Supports `integer_per_element` abi.
229 elementwise_gpr: ArgsInfo,231 elementwise_gpr: ArgsInfo,
230 /// Supports `sse_per_element` abi232 /// Supports `sse_per_element` abi.
231 elementwise_sse: ArgsInfo,233 elementwise_sse: ArgsInfo,
232 /// Supports `sse_per_xword` abi234 /// Supports `sse_per_xword` abi.
233 xwordwise_sse: ArgsInfo,235 xwordwise_sse: ArgsInfo,
234 /// Supports `sse_per_yword` abi236 /// Supports `sse_per_yword` abi.
235 ywordwise_sse: ArgsInfo,237 ywordwise_sse: ArgsInfo,
236 /// Supports `sse_per_zword` abi238 /// Supports `sse_per_zword` abi.
237 zwordwise_sse: ArgsInfo,239 zwordwise_sse: ArgsInfo,
238 /// This indicates that we have already allocated a frame index for this instruction,240 /// This indicates that we have already allocated a frame index for this instruction,
239 /// but it has not been spilled there yet in the current control flow.241 /// but it has not been spilled there yet in the current control flow.
...@@ -261,6 +263,7 @@ pub const MCValue = union(enum) {...@@ -261,6 +263,7 @@ pub const MCValue = union(enum) {
261 .lea_lazy_sym,263 .lea_lazy_sym,
262 .lea_extern_func,264 .lea_extern_func,
263 .load_extern_func,265 .load_extern_func,
266 .register_tee,
264 .elementwise_gpr,267 .elementwise_gpr,
265 .elementwise_sse,268 .elementwise_sse,
266 .xwordwise_sse,269 .xwordwise_sse,
...@@ -386,6 +389,7 @@ pub const MCValue = union(enum) {...@@ -386,6 +389,7 @@ pub const MCValue = union(enum) {
386 .lea_uav,389 .lea_uav,
387 .lea_lazy_sym,390 .lea_lazy_sym,
388 .lea_extern_func,391 .lea_extern_func,
392 .register_tee,
389 .elementwise_gpr,393 .elementwise_gpr,
390 .elementwise_sse,394 .elementwise_sse,
391 .xwordwise_sse,395 .xwordwise_sse,
...@@ -427,6 +431,7 @@ pub const MCValue = union(enum) {...@@ -427,6 +431,7 @@ pub const MCValue = union(enum) {
427 .load_uav,431 .load_uav,
428 .load_lazy_sym,432 .load_lazy_sym,
429 .load_extern_func,433 .load_extern_func,
434 .register_tee,
430 .elementwise_gpr,435 .elementwise_gpr,
431 .elementwise_sse,436 .elementwise_sse,
432 .xwordwise_sse,437 .xwordwise_sse,
...@@ -453,6 +458,7 @@ pub const MCValue = union(enum) {...@@ -453,6 +458,7 @@ pub const MCValue = union(enum) {
453 .unreach,458 .unreach,
454 .dead,459 .dead,
455 .undef,460 .undef,
461 .register_tee,
456 .elementwise_gpr,462 .elementwise_gpr,
457 .elementwise_sse,463 .elementwise_sse,
458 .xwordwise_sse,464 .xwordwise_sse,
...@@ -511,6 +517,7 @@ pub const MCValue = union(enum) {...@@ -511,6 +517,7 @@ pub const MCValue = union(enum) {
511 .register_mask,517 .register_mask,
512 .indirect_load_frame,518 .indirect_load_frame,
513 .lea_frame,519 .lea_frame,
520 .register_tee,
514 .elementwise_gpr,521 .elementwise_gpr,
515 .elementwise_sse,522 .elementwise_sse,
516 .xwordwise_sse,523 .xwordwise_sse,
...@@ -593,6 +600,7 @@ pub const MCValue = union(enum) {...@@ -593,6 +600,7 @@ pub const MCValue = union(enum) {
593 .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),600 .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
594 .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}),601 .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}),
595 .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}),602 .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}),
603 .register_tee => |pl| try w.print("tee:{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
596 .elementwise_gpr => |pl| try w.print("elementwise:gpr{d}:[{f} + 0x{x}]", .{604 .elementwise_gpr => |pl| try w.print("elementwise:gpr{d}:[{f} + 0x{x}]", .{
597 pl.info.reg_index, pl.frame_index, pl.info.frame_off,605 pl.info.reg_index, pl.frame_index, pl.info.frame_off,
598 }),606 }),
...@@ -640,6 +648,7 @@ const InstTracking = struct {...@@ -640,6 +648,7 @@ const InstTracking = struct {
640 .lea_extern_func,648 .lea_extern_func,
641 => result,649 => result,
642 .dead,650 .dead,
651 .register_tee,
643 .elementwise_gpr,652 .elementwise_gpr,
644 .elementwise_sse,653 .elementwise_sse,
645 .xwordwise_sse,654 .xwordwise_sse,
...@@ -756,6 +765,7 @@ const InstTracking = struct {...@@ -756,6 +765,7 @@ const InstTracking = struct {
756 .register_overflow,765 .register_overflow,
757 .register_mask,766 .register_mask,
758 .indirect,767 .indirect,
768 .register_tee,
759 .elementwise_gpr,769 .elementwise_gpr,
760 .elementwise_sse,770 .elementwise_sse,
761 .xwordwise_sse,771 .xwordwise_sse,
...@@ -174266,15 +174276,16 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co...@@ -174266,15 +174276,16 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co
174266 const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).array.len]RegisterLock;174276 const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).array.len]RegisterLock;
174267 const bfa_buf_len = if (opts.update_tracking) 0 else 1;174277 const bfa_buf_len = if (opts.update_tracking) 0 else 1;
174268 var bfa_buf: [bfa_buf_len]ExpectedContents = undefined;174278 var bfa_buf: [bfa_buf_len]ExpectedContents = undefined;
174269 var stack = if (opts.update_tracking) {} else std.heap.BufferFirstAllocator.init(@ptrCast(&bfa_buf), self.gpa);174279 var stack = if (!opts.update_tracking) std.heap.BufferFirstAllocator.init(@ptrCast(&bfa_buf), self.gpa);
174280 const allocator = if (!opts.update_tracking) stack.allocator();
174270174281
174271 var reg_locks = if (opts.update_tracking) {} else try std.array_list.Managed(RegisterLock).initCapacity(174282 var reg_locks = if (!opts.update_tracking) try std.ArrayList(RegisterLock).initCapacity(
174272 stack.allocator(),174283 allocator,
174273 @typeInfo(ExpectedContents).array.len,174284 @typeInfo(ExpectedContents).array.len,
174274 );174285 );
174275 defer if (!opts.update_tracking) {174286 defer if (!opts.update_tracking) {
174276 for (reg_locks.items) |lock| self.register_manager.unlockReg(lock);174287 for (reg_locks.items) |lock| self.register_manager.unlockReg(lock);
174277 reg_locks.deinit();174288 reg_locks.deinit(allocator);
174278 };174289 };
174279174290
174280 for (174291 for (
...@@ -174304,7 +174315,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co...@@ -174304,7 +174315,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co
174304 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking);174315 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking);
174305 }174316 }
174306 } else if (target_maybe_inst) |_|174317 } else if (target_maybe_inst) |_|
174307 try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index));174318 try reg_locks.append(allocator, self.register_manager.lockRegIndexAssumeUnused(reg_index));
174308 }174319 }
174309 if (opts.emit_instructions) if (self.eflags_inst) |inst|174320 if (opts.emit_instructions) if (self.eflags_inst) |inst|
174310 try self.inst_tracking.getPtr(inst).?.spill(self, inst);174321 try self.inst_tracking.getPtr(inst).?.spill(self, inst);
...@@ -174517,6 +174528,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -174517,6 +174528,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
174517 .register_overflow,174528 .register_overflow,
174518 .register_mask,174529 .register_mask,
174519 .indirect_load_frame,174530 .indirect_load_frame,
174531 .register_tee,
174520 .elementwise_gpr,174532 .elementwise_gpr,
174521 .elementwise_sse,174533 .elementwise_sse,
174522 .xwordwise_sse,174534 .xwordwise_sse,
...@@ -174574,6 +174586,7 @@ fn store(...@@ -174574,6 +174586,7 @@ fn store(
174574 .register_overflow,174586 .register_overflow,
174575 .register_mask,174587 .register_mask,
174576 .indirect_load_frame,174588 .indirect_load_frame,
174589 .register_tee,
174577 .elementwise_gpr,174590 .elementwise_gpr,
174578 .elementwise_sse,174591 .elementwise_sse,
174579 .xwordwise_sse,174592 .xwordwise_sse,
...@@ -174628,6 +174641,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -174628,6 +174641,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
174628 .lea_uav,174641 .lea_uav,
174629 .lea_lazy_sym,174642 .lea_lazy_sym,
174630 .lea_extern_func,174643 .lea_extern_func,
174644 .register_tee,
174631 .elementwise_gpr,174645 .elementwise_gpr,
174632 .elementwise_sse,174646 .elementwise_sse,
174633 .xwordwise_sse,174647 .xwordwise_sse,
...@@ -175322,6 +175336,7 @@ fn genBinOpMir(...@@ -175322,6 +175336,7 @@ fn genBinOpMir(
175322 .lea_lazy_sym,175336 .lea_lazy_sym,
175323 .lea_extern_func,175337 .lea_extern_func,
175324 .indirect_load_frame,175338 .indirect_load_frame,
175339 .register_tee,
175325 .elementwise_gpr,175340 .elementwise_gpr,
175326 .elementwise_sse,175341 .elementwise_sse,
175327 .xwordwise_sse,175342 .xwordwise_sse,
...@@ -175363,6 +175378,7 @@ fn genBinOpMir(...@@ -175363,6 +175378,7 @@ fn genBinOpMir(
175363 .register_overflow,175378 .register_overflow,
175364 .register_mask,175379 .register_mask,
175365 .indirect_load_frame,175380 .indirect_load_frame,
175381 .register_tee,
175366 .elementwise_gpr,175382 .elementwise_gpr,
175367 .elementwise_sse,175383 .elementwise_sse,
175368 .xwordwise_sse,175384 .xwordwise_sse,
...@@ -175539,6 +175555,7 @@ fn genBinOpMir(...@@ -175539,6 +175555,7 @@ fn genBinOpMir(
175539 .register_overflow,175555 .register_overflow,
175540 .register_mask,175556 .register_mask,
175541 .indirect_load_frame,175557 .indirect_load_frame,
175558 .register_tee,
175542 .elementwise_gpr,175559 .elementwise_gpr,
175543 .elementwise_sse,175560 .elementwise_sse,
175544 .xwordwise_sse,175561 .xwordwise_sse,
...@@ -175647,6 +175664,7 @@ fn genBinOpMir(...@@ -175647,6 +175664,7 @@ fn genBinOpMir(
175647 .register_overflow,175664 .register_overflow,
175648 .register_mask,175665 .register_mask,
175649 .indirect_load_frame,175666 .indirect_load_frame,
175667 .register_tee,
175650 .elementwise_gpr,175668 .elementwise_gpr,
175651 .elementwise_sse,175669 .elementwise_sse,
175652 .xwordwise_sse,175670 .xwordwise_sse,
...@@ -176002,6 +176020,7 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue...@@ -176002,6 +176020,7 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue
176002 .none,176020 .none,
176003 .unreach,176021 .unreach,
176004 .dead,176022 .dead,
176023 .register_tee,
176005 .elementwise_gpr,176024 .elementwise_gpr,
176006 .elementwise_sse,176025 .elementwise_sse,
176007 .xwordwise_sse,176026 .xwordwise_sse,
...@@ -176060,6 +176079,7 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue...@@ -176060,6 +176079,7 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue
176060 .none,176079 .none,
176061 .unreach,176080 .unreach,
176062 .dead,176081 .dead,
176082 .register_tee,
176063 .elementwise_gpr,176083 .elementwise_gpr,
176064 .elementwise_sse,176084 .elementwise_sse,
176065 .xwordwise_sse,176085 .xwordwise_sse,
...@@ -176197,14 +176217,14 @@ fn genCall(cg: *CodeGen, info: union(enum) {...@@ -176197,14 +176217,14 @@ fn genCall(cg: *CodeGen, info: union(enum) {
176197176217
176198 const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);176218 const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);
176199 defer allocator.free(var_args);176219 defer allocator.free(var_args);
176200 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;176220 @memcpy(var_args, arg_types[fn_info.param_types.len..]);
176201176221
176202 const frame_indices = try allocator.alloc(FrameIndex, args.len);176222 const frame_indices = try allocator.alloc(FrameIndex, args.len);
176203 defer allocator.free(frame_indices);176223 defer allocator.free(frame_indices);
176204176224
176205 var reg_locks: std.array_list.Managed(?RegisterLock) = .init(allocator);176225 var reg_locks: std.ArrayList(?RegisterLock) = .empty;
176206 defer reg_locks.deinit();176226 defer reg_locks.deinit(allocator);
176207 try reg_locks.ensureTotalCapacity(16);176227 try reg_locks.ensureTotalCapacity(allocator, 16);
176208 defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| cg.register_manager.unlockReg(lock);176228 defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| cg.register_manager.unlockReg(lock);
176209176229
176210 var call_info = try cg.resolveCallingConventionValues(fn_info, var_args, .call_frame);176230 var call_info = try cg.resolveCallingConventionValues(fn_info, var_args, .call_frame);
...@@ -176235,169 +176255,165 @@ fn genCall(cg: *CodeGen, info: union(enum) {...@@ -176235,169 +176255,165 @@ fn genCall(cg: *CodeGen, info: union(enum) {
176235 .indirect => |reg_off| try cg.register_manager.getReg(reg_off.reg, null),176255 .indirect => |reg_off| try cg.register_manager.getReg(reg_off.reg, null),
176236 else => unreachable,176256 else => unreachable,
176237 }176257 }
176238 for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, *frame_index, arg_i|176258 for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index| switch (dst_arg) {
176239 switch (dst_arg) {176259 .none => {},
176240 .none => {},176260 .register => |reg| {
176241 .register => |reg| {176261 try cg.register_manager.getReg(reg, null);
176262 try reg_locks.append(allocator, cg.register_manager.lockReg(reg));
176263 },
176264 inline .register_pair, .register_triple, .register_quadruple => |regs| {
176265 for (regs) |reg| try cg.register_manager.getReg(reg, null);
176266 try reg_locks.appendSlice(allocator, &cg.register_manager.lockRegs(regs.len, regs));
176267 },
176268 .indirect => |reg_off| {
176269 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));
176270 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
176271 try cg.register_manager.getReg(reg_off.reg, null);
176272 try reg_locks.append(allocator, cg.register_manager.lockReg(reg_off.reg));
176273 },
176274 .indirect_load_frame => |frame_addr| {
176275 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));
176276 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
176277 try cg.genSetMem(
176278 .{ .frame = frame_addr.index },
176279 frame_addr.off,
176280 .usize,
176281 .{ .lea_frame = .{ .index = frame_index.* } },
176282 opts,
176283 );
176284 },
176285 .load_frame => {
176286 try cg.genCopy(arg_ty, dst_arg, src_arg, opts);
176287 try cg.freeValue(src_arg, .{});
176288 },
176289 .register_tee => |regs| {
176290 try reg_locks.ensureUnusedCapacity(allocator, regs.len);
176291 for (regs) |reg| if (reg != .none) {
176242 try cg.register_manager.getReg(reg, null);176292 try cg.register_manager.getReg(reg, null);
176243 try reg_locks.append(cg.register_manager.lockReg(reg));176293 reg_locks.appendAssumeCapacity(cg.register_manager.lockReg(reg));
176244176294 };
176245 if (fn_info.is_var_args and176295 },
176246 fn_info.cc == .x86_64_win and176296 .elementwise_gpr, .elementwise_sse => |regs_frame_addr| {
176247 reg.class() == .sse and176297 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{
176248 arg_i < abi.Win64.c_abi_int_param_regs.len)176298 .base = .{ .reg = try cg.copyToTmpRegister(.usize, switch (src_arg) {
176249 {176299 else => src_arg,
176250 // Floating point arguments must be duplicated into the equivalent integer registers on this ABI176300 .air_ref => |src_ref| try cg.resolveInst(src_ref),
176251 const int_reg = abi.Win64.c_abi_int_param_regs[arg_i];176301 }.address()) },
176252 try reg_locks.append(cg.register_manager.lockReg(int_reg));176302 .mod = .{ .rm = .{ .size = .dword } },
176253 }176303 };
176254 },176304 const src_lock = switch (src_mem.base) {
176255 .register_pair => |regs| {176305 .reg => |src_reg| cg.register_manager.lockReg(src_reg),
176256 for (regs) |reg| try cg.register_manager.getReg(reg, null);176306 else => null,
176257 try reg_locks.appendSlice(&cg.register_manager.lockRegs(2, regs));176307 };
176258 },176308 defer if (src_lock) |lock| cg.register_manager.unlockReg(lock);
176259 .indirect => |reg_off| {
176260 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));
176261 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
176262 try cg.register_manager.getReg(reg_off.reg, null);
176263 try reg_locks.append(cg.register_manager.lockReg(reg_off.reg));
176264 },
176265 .indirect_load_frame => |frame_addr| {
176266 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));
176267 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
176268 try cg.genSetMem(
176269 .{ .frame = frame_addr.index },
176270 frame_addr.off,
176271 .usize,
176272 .{ .lea_frame = .{ .index = frame_index.* } },
176273 opts,
176274 );
176275 },
176276 .load_frame => {
176277 try cg.genCopy(arg_ty, dst_arg, src_arg, opts);
176278 try cg.freeValue(src_arg, .{});
176279 },
176280 .elementwise_gpr, .elementwise_sse => |regs_frame_addr| {
176281 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{
176282 .base = .{ .reg = try cg.copyToTmpRegister(.usize, switch (src_arg) {
176283 else => src_arg,
176284 .air_ref => |src_ref| try cg.resolveInst(src_ref),
176285 }.address()) },
176286 .mod = .{ .rm = .{ .size = .dword } },
176287 };
176288 const src_lock = switch (src_mem.base) {
176289 .reg => |src_reg| cg.register_manager.lockReg(src_reg),
176290 else => null,
176291 };
176292 defer if (src_lock) |lock| cg.register_manager.unlockReg(lock);
176293
176294 const elem_rc: Register.Class, const param_regs = switch (dst_arg) {
176295 else => unreachable,
176296 .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) },
176297 .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) },
176298 };
176299 const len = arg_ty.vectorLen(zcu);
176300 const param_reg_len: u31 =
176301 @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len));
176302176309
176303 if (len - param_reg_len > 0) {176310 const elem_rc: Register.Class, const param_regs = switch (dst_arg) {
176304 const index_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp);176311 else => unreachable,
176305 const index_lock = cg.register_manager.lockRegAssumeUnused(index_reg);176312 .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) },
176306 defer cg.register_manager.unlockReg(index_lock);176313 .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) },
176307 try cg.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(param_reg_len));176314 };
176315 const len = arg_ty.vectorLen(zcu);
176316 const param_reg_len: u31 =
176317 @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len));
176308176318
176309 const loop: Mir.Inst.Index = @intCast(cg.mir_instructions.len);176319 if (len - param_reg_len > 0) {
176310 const elem_ty = arg_ty.childType(zcu);176320 const index_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp);
176311 if (elem_ty.toIntern() == .bool_type) {176321 const index_lock = cg.register_manager.lockRegAssumeUnused(index_reg);
176312 try cg.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32());176322 defer cg.register_manager.unlockReg(index_lock);
176313 try cg.asmSetccMemory(.c, .{176323 try cg.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(param_reg_len));
176314 .base = .{ .frame = regs_frame_addr.frame_index },
176315 .mod = .{ .rm = .{
176316 .size = .byte,
176317 .index = index_reg.to64(),
176318 .scale = .@"8",
176319 .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len,
176320 } },
176321 });
176322 } else {
176323 const elem_reg =
176324 try cg.register_manager.allocReg(null, regSetForRegClass(elem_rc));
176325 const elem_lock = cg.register_manager.lockRegAssumeUnused(elem_reg);
176326 defer cg.register_manager.unlockReg(elem_lock);
176327 const elem_size = cg.memSize(elem_ty, .general_purpose);
176328 const elem_alias = elem_reg.toSize(elem_size, cg.target);
176329176324
176330 const strat = try cg.moveStrategy(elem_ty, elem_rc, true);176325 const loop: Mir.Inst.Index = @intCast(cg.mir_instructions.len);
176331 assert(src_mem.mod.rm.index == .none and src_mem.mod.rm.scale == .@"1");176326 const elem_ty = arg_ty.childType(zcu);
176332 try strat.read(cg, elem_alias, .{176327 if (elem_ty.toIntern() == .bool_type) {
176333 .base = src_mem.base,176328 try cg.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32());
176334 .mod = .{ .rm = .{176329 try cg.asmSetccMemory(.c, .{
176335 .size = elem_size,176330 .base = .{ .frame = regs_frame_addr.frame_index },
176336 .index = index_reg.to64(),176331 .mod = .{ .rm = .{
176337 .scale = .fromFactor(@intCast(@divExact(elem_size.bitSize(cg.target), 8))),176332 .size = .byte,
176338 .disp = src_mem.mod.rm.disp,176333 .index = index_reg.to64(),
176339 } },176334 .scale = .@"8",
176340 });176335 .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len,
176341 try strat.write(cg, .{176336 } },
176342 .base = .{ .frame = regs_frame_addr.frame_index },176337 });
176343 .mod = .{ .rm = .{176338 } else {
176344 .size = elem_size,176339 const elem_reg =
176345 .index = index_reg.to64(),176340 try cg.register_manager.allocReg(null, regSetForRegClass(elem_rc));
176346 .scale = .@"8",176341 const elem_lock = cg.register_manager.lockRegAssumeUnused(elem_reg);
176347 .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len,176342 defer cg.register_manager.unlockReg(elem_lock);
176348 } },176343 const elem_size = cg.memSize(elem_ty, .general_purpose);
176349 }, elem_alias);176344 const elem_alias = elem_reg.toSize(elem_size, cg.target);
176350 }176345
176351 if (cg.hasFeature(.slow_incdec)) {176346 const strat = try cg.moveStrategy(elem_ty, elem_rc, true);
176352 try cg.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));176347 assert(src_mem.mod.rm.index == .none and src_mem.mod.rm.scale == .@"1");
176353 } else {176348 try strat.read(cg, elem_alias, .{
176354 try cg.asmRegister(.{ ._c, .in }, index_reg.to32());176349 .base = src_mem.base,
176355 }176350 .mod = .{ .rm = .{
176356 try cg.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(len));176351 .size = elem_size,
176357 _ = try cg.asmJccReloc(.b, loop);176352 .index = index_reg.to64(),
176353 .scale = .fromFactor(@intCast(@divExact(elem_size.bitSize(cg.target), 8))),
176354 .disp = src_mem.mod.rm.disp,
176355 } },
176356 });
176357 try strat.write(cg, .{
176358 .base = .{ .frame = regs_frame_addr.frame_index },
176359 .mod = .{ .rm = .{
176360 .size = elem_size,
176361 .index = index_reg.to64(),
176362 .scale = .@"8",
176363 .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len,
176364 } },
176365 }, elem_alias);
176358 }176366 }
176359176367 if (cg.hasFeature(.slow_incdec)) {
176360 for (param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len]) |dst_reg| {176368 try cg.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
176361 try cg.register_manager.getReg(dst_reg, null);176369 } else {
176362 try reg_locks.append(cg.register_manager.lockReg(dst_reg));176370 try cg.asmRegister(.{ ._c, .in }, index_reg.to32());
176363 }176371 }
176364 },176372 try cg.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(len));
176365 .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| {176373 _ = try cg.asmJccReloc(.b, loop);
176366 const elem_size: u31 = switch (dst_arg) {176374 }
176367 else => unreachable,
176368 .xwordwise_sse => 16,
176369 .ywordwise_sse => 32,
176370 .zwordwise_sse => 64,
176371 };
176372 const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc);
176373 const arg_size: u31 = @intCast(arg_ty.abiSize(zcu));
176374 const len = @divExact(arg_size, elem_size);
176375 const param_gpr_len: u31 =
176376 @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len));
176377176375
176378 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));176376 for (param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len]) |dst_reg| {
176379 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);176377 try cg.register_manager.getReg(dst_reg, null);
176380176378 try reg_locks.append(allocator, cg.register_manager.lockReg(dst_reg));
176381 var frame_offset: i32 = regs_frame_addr.info.frame_off;176379 }
176382 var arg_offset = elem_size * param_gpr_len;176380 },
176383 while (arg_size - arg_offset != 0) : ({176381 .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| {
176384 frame_offset += 8;176382 const elem_size: u31 = switch (dst_arg) {
176385 arg_offset += elem_size;176383 else => unreachable,
176386 }) try cg.genSetMem(176384 .xwordwise_sse => 16,
176387 .{ .frame = regs_frame_addr.frame_index },176385 .ywordwise_sse => 32,
176388 frame_offset,176386 .zwordwise_sse => 64,
176389 .usize,176387 };
176390 .{ .lea_frame = .{ .index = frame_index.*, .off = arg_offset } },176388 const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc);
176391 opts,176389 const arg_size: u31 = @intCast(arg_ty.abiSize(zcu));
176392 );176390 const len = @divExact(arg_size, elem_size);
176391 const param_gpr_len: u31 =
176392 @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len));
176393
176394 frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu));
176395 try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
176396
176397 var frame_offset: i32 = regs_frame_addr.info.frame_off;
176398 var arg_offset = elem_size * param_gpr_len;
176399 while (arg_size - arg_offset != 0) : ({
176400 frame_offset += 8;
176401 arg_offset += elem_size;
176402 }) try cg.genSetMem(
176403 .{ .frame = regs_frame_addr.frame_index },
176404 frame_offset,
176405 .usize,
176406 .{ .lea_frame = .{ .index = frame_index.*, .off = arg_offset } },
176407 opts,
176408 );
176393176409
176394 for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| {176410 for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| {
176395 try cg.register_manager.getReg(dst_reg, null);176411 try cg.register_manager.getReg(dst_reg, null);
176396 try reg_locks.append(cg.register_manager.lockReg(dst_reg));176412 try reg_locks.append(allocator, cg.register_manager.lockReg(dst_reg));
176397 }176413 }
176398 },176414 },
176399 else => unreachable,176415 else => unreachable,
176400 };176416 };
176401176417
176402 if (call_info.err_ret_trace_reg != .none) {176418 if (call_info.err_ret_trace_reg != .none) {
176403 if (cg.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| {176419 if (cg.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| {
...@@ -176406,7 +176422,7 @@ fn genCall(cg: *CodeGen, info: union(enum) {...@@ -176406,7 +176422,7 @@ fn genCall(cg: *CodeGen, info: union(enum) {
176406 else => true,176422 else => true,
176407 }) {176423 }) {
176408 try cg.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index);176424 try cg.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index);
176409 try reg_locks.append(cg.register_manager.lockReg(call_info.err_ret_trace_reg));176425 try reg_locks.append(allocator, cg.register_manager.lockReg(call_info.err_ret_trace_reg));
176410176426
176411 try cg.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, opts);176427 try cg.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, opts);
176412 err_ret_trace.trackMaterialize(err_ret_trace_index, .{176428 err_ret_trace.trackMaterialize(err_ret_trace_index, .{
...@@ -176427,114 +176443,102 @@ fn genCall(cg: *CodeGen, info: union(enum) {...@@ -176427,114 +176443,102 @@ fn genCall(cg: *CodeGen, info: union(enum) {
176427 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },176443 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
176428 }, opts);176444 }, opts);
176429 call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };176445 call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
176430 try reg_locks.append(cg.register_manager.lockReg(reg_off.reg));176446 try reg_locks.append(allocator, cg.register_manager.lockReg(reg_off.reg));
176431 },176447 },
176432 else => unreachable,176448 else => unreachable,
176433 }176449 }
176434176450
176435 for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, frame_index, arg_i|176451 for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| switch (dst_arg) {
176436 switch (dst_arg) {176452 .none, .load_frame, .indirect_load_frame => {},
176437 .none, .load_frame, .indirect_load_frame => {},176453 .register => |dst_reg| try cg.genSetReg(registerAlias(
176438 .register => |dst_reg| switch (fn_info.cc) {176454 dst_reg,
176439 else => try cg.genSetReg(registerAlias(176455 @intCast(cg.unalignedSize(arg_ty)),
176440 dst_reg,176456 ), arg_ty, src_arg, opts),
176441 @intCast(arg_ty.abiSize(zcu)),176457 .register_pair,
176442 ), arg_ty, src_arg, opts),176458 .register_triple,
176443 .x86_64_sysv, .x86_64_win => {176459 .register_quadruple,
176444 const promoted_ty = cg.promoteInt(arg_ty);176460 => try cg.genCopy(arg_ty, dst_arg, src_arg, opts),
176445 const promoted_unaligned_size: u32 = @intCast(cg.unalignedSize(promoted_ty));176461 .indirect => |reg_off| try cg.genSetReg(reg_off.reg, .usize, .{
176446 const dst_alias = registerAlias(dst_reg, promoted_unaligned_size);176462 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
176447 try cg.genSetReg(dst_alias, promoted_ty, src_arg, opts);176463 }, opts),
176448 if (promoted_ty.toIntern() != arg_ty.toIntern())176464 .register_tee => |dst_regs| {
176449 try cg.truncateRegister(arg_ty, dst_alias);176465 try cg.genSetReg(dst_regs[0], arg_ty, src_arg, opts);
176450176466 for (dst_regs[1..]) |dst_reg| if (dst_reg != .none) try cg.genSetReg(dst_reg, arg_ty, .{
176451 if (fn_info.is_var_args and176467 .register = dst_regs[0],
176452 fn_info.cc == .x86_64_win and176468 }, opts);
176453 dst_reg.class() == .sse and176469 },
176454 arg_i < abi.Win64.c_abi_int_param_regs.len)176470 .elementwise_gpr, .elementwise_sse => |regs_frame_addr| {
176455 {176471 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{
176456 const int_dst_reg = abi.Win64.c_abi_int_param_regs[arg_i];176472 .base = .{ .reg = try cg.copyToTmpRegister(
176457 const int_dst_alias = registerAlias(int_dst_reg, promoted_unaligned_size);176473 .usize,
176458 try cg.genSetReg(int_dst_alias, promoted_ty, .{ .register = dst_alias }, opts);176474 switch (src_arg) {
176459 }176475 else => src_arg,
176460 },176476 .air_ref => |src_ref| try cg.resolveInst(src_ref),
176461 },176477 }.address(),
176462 .register_pair => try cg.genCopy(arg_ty, dst_arg, src_arg, opts),176478 ) },
176463 .indirect => |reg_off| try cg.genSetReg(reg_off.reg, .usize, .{176479 .mod = .{ .rm = .{ .size = .dword } },
176464 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },176480 };
176465 }, opts),176481 const src_lock = switch (src_mem.base) {
176466 .elementwise_gpr, .elementwise_sse => |regs_frame_addr| {176482 .reg => |src_reg| cg.register_manager.lockReg(src_reg),
176467 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{176483 else => null,
176468 .base = .{ .reg = try cg.copyToTmpRegister(176484 };
176469 .usize,176485 defer if (src_lock) |lock| cg.register_manager.unlockReg(lock);
176470 switch (src_arg) {
176471 else => src_arg,
176472 .air_ref => |src_ref| try cg.resolveInst(src_ref),
176473 }.address(),
176474 ) },
176475 .mod = .{ .rm = .{ .size = .dword } },
176476 };
176477 const src_lock = switch (src_mem.base) {
176478 .reg => |src_reg| cg.register_manager.lockReg(src_reg),
176479 else => null,
176480 };
176481 defer if (src_lock) |lock| cg.register_manager.unlockReg(lock);
176482176486
176483 const elem_rc: Register.Class, const param_regs = switch (dst_arg) {176487 const elem_rc: Register.Class, const param_regs = switch (dst_arg) {
176484 else => unreachable,176488 else => unreachable,
176485 .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) },176489 .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) },
176486 .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) },176490 .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) },
176487 };176491 };
176488 const len = arg_ty.vectorLen(zcu);176492 const len = arg_ty.vectorLen(zcu);
176489 const elem_ty = arg_ty.childType(zcu);176493 const elem_ty = arg_ty.childType(zcu);
176490 const elem_size = cg.memSize(elem_ty, .general_purpose);176494 const elem_size = cg.memSize(elem_ty, .general_purpose);
176491 const elem_abi_size = @divExact(elem_size.bitSize(cg.target), 8);176495 const elem_abi_size = @divExact(elem_size.bitSize(cg.target), 8);
176492 const param_reg_len: u31 =176496 const param_reg_len: u31 =
176493 @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len));176497 @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len));
176494 const strat = if (elem_ty.toIntern() == .bool_type) strat: {176498 const strat = if (elem_ty.toIntern() == .bool_type) strat: {
176495 try cg.spillEflagsIfOccupied();176499 try cg.spillEflagsIfOccupied();
176496 break :strat undefined;176500 break :strat undefined;
176497 } else try cg.moveStrategy(elem_ty, elem_rc, true);176501 } else try cg.moveStrategy(elem_ty, elem_rc, true);
176498 for (176502 for (
176499 param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len],176503 param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len],
176500 0..,176504 0..,
176501 ) |dst_reg, elem_index| if (elem_ty.toIntern() == .bool_type) {176505 ) |dst_reg, elem_index| if (elem_ty.toIntern() == .bool_type) {
176502 try cg.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32());176506 try cg.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32());
176503 try cg.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index));176507 try cg.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index));
176504 try cg.asmSetccRegister(.c, dst_reg.to8());176508 try cg.asmSetccRegister(.c, dst_reg.to8());
176505 } else try strat.read(cg, dst_reg.toSize(elem_size, cg.target), .{176509 } else try strat.read(cg, dst_reg.toSize(elem_size, cg.target), .{
176506 .base = src_mem.base,176510 .base = src_mem.base,
176507 .mod = .{ .rm = .{176511 .mod = .{ .rm = .{
176508 .size = elem_size,176512 .size = elem_size,
176509 .disp = src_mem.mod.rm.disp + @as(u31, @intCast(elem_abi_size * elem_index)),176513 .disp = src_mem.mod.rm.disp + @as(u31, @intCast(elem_abi_size * elem_index)),
176510 } },176514 } },
176511 });176515 });
176512 },176516 },
176513 .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| {176517 .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| {
176514 const elem_size: u31 = switch (dst_arg) {176518 const elem_size: u31 = switch (dst_arg) {
176515 else => unreachable,176519 else => unreachable,
176516 .xwordwise_sse => 16,176520 .xwordwise_sse => 16,
176517 .ywordwise_sse => 32,176521 .ywordwise_sse => 32,
176518 .zwordwise_sse => 64,176522 .zwordwise_sse => 64,
176519 };176523 };
176520 const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc);176524 const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc);
176521 const len = @divExact(arg_ty.abiSize(zcu), elem_size);176525 const len = @divExact(arg_ty.abiSize(zcu), elem_size);
176522 const param_gpr_len: u31 =176526 const param_gpr_len: u31 =
176523 @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len));176527 @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len));
176524176528
176525 var arg_offset: u31 = 0;176529 var arg_offset: u31 = 0;
176526 for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| {176530 for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| {
176527 try cg.genSetReg(176531 try cg.genSetReg(
176528 dst_reg,176532 dst_reg,
176529 .usize,176533 .usize,
176530 .{ .lea_frame = .{ .index = frame_index, .off = arg_offset } },176534 .{ .lea_frame = .{ .index = frame_index, .off = arg_offset } },
176531 opts,176535 opts,
176532 );176536 );
176533 arg_offset += elem_size;176537 arg_offset += elem_size;
176534 }176538 }
176535 },176539 },
176536 else => unreachable,176540 else => unreachable,
176537 };176541 };
176538176542
176539 if (fn_info.is_var_args and fn_info.cc == .x86_64_sysv)176543 if (fn_info.is_var_args and fn_info.cc == .x86_64_sysv)
176540 try cg.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count));176544 try cg.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count));
...@@ -177474,13 +177478,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177474,13 +177478,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177474 const inputs = unwrapped_asm.inputs;177478 const inputs = unwrapped_asm.inputs;
177475177479
177476 var result: MCValue = .none;177480 var result: MCValue = .none;
177477 var args: std.array_list.Managed(MCValue) = .init(self.gpa);177481 var args = try self.gpa.alloc(MCValue, outputs.len + inputs.len);
177478 try args.ensureTotalCapacity(outputs.len + inputs.len);177482 var args_len: usize = 0;
177479 defer {177483 defer {
177480 for (args.items) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{177484 for (args[0..args_len]) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{
177481 .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue,177485 .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue,
177482 });177486 });
177483 args.deinit();177487 self.gpa.free(args);
177484 }177488 }
177485 var arg_map: std.StringHashMap(u8) = .init(self.gpa);177489 var arg_map: std.StringHashMap(u8) = .init(self.gpa);
177486 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));177490 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
...@@ -177539,10 +177543,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177539,10 +177543,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177539 return self.fail("invalid register constraint: '{s}'", .{out.constraint})177543 return self.fail("invalid register constraint: '{s}'", .{out.constraint})
177540 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {177544 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {
177541 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;177545 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;
177542 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{177546 if (index >= args_len) return self.fail("constraint out of bounds: '{s}'", .{
177543 out.constraint,177547 out.constraint,
177544 });177548 });
177545 break :arg_mcv args.items[index];177549 break :arg_mcv args[index];
177546 } else return self.fail("invalid constraint: '{s}'", .{out.constraint});177550 } else return self.fail("invalid constraint: '{s}'", .{out.constraint});
177547 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {177551 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
177548 const ptr_mcv = try self.resolveInst(out.operand);177552 const ptr_mcv = try self.resolveInst(out.operand);
...@@ -177560,8 +177564,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177560,8 +177564,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177560 _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index);177564 _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index);
177561 };177565 };
177562 if (!std.mem.eql(u8, out.name, "_"))177566 if (!std.mem.eql(u8, out.name, "_"))
177563 arg_map.putAssumeCapacityNoClobber(out.name, @intCast(args.items.len));177567 arg_map.putAssumeCapacityNoClobber(out.name, @intCast(args_len));
177564 args.appendAssumeCapacity(arg_mcv);177568 args[args_len] = arg_mcv;
177569 args_len += 1;
177565 if (out.operand == .none) result = arg_mcv;177570 if (out.operand == .none) result = arg_mcv;
177566 if (is_read) try self.load(arg_mcv, self.typeOf(out.operand), .{ .air_ref = out.operand });177571 if (is_read) try self.load(arg_mcv, self.typeOf(out.operand), .{ .air_ref = out.operand });
177567 }177572 }
...@@ -177644,17 +177649,19 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177644,17 +177649,19 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177644 break :arg .{ .register = reg };177649 break :arg .{ .register = reg };
177645 } else if (in.constraint.len == 1 and std.ascii.isDigit(in.constraint[0])) arg: {177650 } else if (in.constraint.len == 1 and std.ascii.isDigit(in.constraint[0])) arg: {
177646 const index = std.fmt.charToDigit(in.constraint[0], 10) catch unreachable;177651 const index = std.fmt.charToDigit(in.constraint[0], 10) catch unreachable;
177647 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{in.constraint});177652 if (index >= args_len) return self.fail("constraint out of bounds: '{s}'", .{in.constraint});
177648 try self.genCopy(ty, args.items[index], input_mcv, .{});177653 try self.genCopy(ty, args[index], input_mcv, .{});
177649 break :arg args.items[index];177654 break :arg args[index];
177650 } else return self.fail("invalid constraint: '{s}'", .{in.constraint});177655 } else return self.fail("invalid constraint: '{s}'", .{in.constraint});
177651 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {177656 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
177652 _ = self.register_manager.lockReg(reg);177657 _ = self.register_manager.lockReg(reg);
177653 };177658 };
177654 if (!std.mem.eql(u8, in.name, "_"))177659 if (!std.mem.eql(u8, in.name, "_"))
177655 arg_map.putAssumeCapacityNoClobber(in.name, @intCast(args.items.len));177660 arg_map.putAssumeCapacityNoClobber(in.name, @intCast(args_len));
177656 args.appendAssumeCapacity(arg_mcv);177661 args[args_len] = arg_mcv;
177662 args_len += 1;
177657 }177663 }
177664 assert(args_len == args.len);
177658177665
177659 const ip = &zcu.intern_pool;177666 const ip = &zcu.intern_pool;
177660 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);177667 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
...@@ -177887,7 +177894,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177887,7 +177894,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177887 op_str[colon_pos + ":".len .. op_str.len - "]".len]177894 op_str[colon_pos + ":".len .. op_str.len - "]".len]
177888 else177895 else
177889 "";177896 "";
177890 op.* = switch (args.items[177897 op.* = switch (args[
177891 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse177898 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
177892 return self.fail("no matching constraint: '{s}'", .{op_str})177899 return self.fail("no matching constraint: '{s}'", .{op_str})
177893 ]) {177900 ]) {
...@@ -178031,7 +178038,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -178031,7 +178038,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
178031 op_str[colon_pos + ":".len .. open - "]".len]178038 op_str[colon_pos + ":".len .. open - "]".len]
178032 else178039 else
178033 "";178040 "";
178034 break :disp switch (args.items[178041 break :disp switch (args[
178035 arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse178042 arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse
178036 return self.fail("no matching constraint: '{s}'", .{op_str})178043 return self.fail("no matching constraint: '{s}'", .{op_str})
178037 ]) {178044 ]) {
...@@ -178191,7 +178198,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -178191,7 +178198,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
178191178198
178192 it = unwrapped_asm.iterateOutputs();178199 it = unwrapped_asm.iterateOutputs();
178193 while (it.next()) |out| {178200 while (it.next()) |out| {
178194 const arg_mcv = args.items[it.current - 1];178201 const arg_mcv = args[it.current - 1];
178195 if (out.operand == .none) continue;178202 if (out.operand == .none) continue;
178196 if (arg_mcv != .register) continue;178203 if (arg_mcv != .register) continue;
178197 if (out.constraint.len == 2 and std.ascii.isDigit(out.constraint[1])) continue;178204 if (out.constraint.len == 2 and std.ascii.isDigit(out.constraint[1])) continue;
...@@ -178638,6 +178645,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -178638,6 +178645,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
178638 .lea_uav,178645 .lea_uav,
178639 .lea_lazy_sym,178646 .lea_lazy_sym,
178640 .lea_extern_func,178647 .lea_extern_func,
178648 .register_tee,
178641 .elementwise_gpr,178649 .elementwise_gpr,
178642 .elementwise_sse,178650 .elementwise_sse,
178643 .xwordwise_sse,178651 .xwordwise_sse,
...@@ -178653,6 +178661,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -178653,6 +178661,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
178653 .dead,178661 .dead,
178654 .undef,178662 .undef,
178655 .register_overflow,178663 .register_overflow,
178664 .register_tee,
178656 .elementwise_gpr,178665 .elementwise_gpr,
178657 .elementwise_sse,178666 .elementwise_sse,
178658 .xwordwise_sse,178667 .xwordwise_sse,
...@@ -178844,6 +178853,7 @@ fn genSetReg(...@@ -178844,6 +178853,7 @@ fn genSetReg(
178844 .unreach,178853 .unreach,
178845 .dead,178854 .dead,
178846 .indirect_load_frame,178855 .indirect_load_frame,
178856 .register_tee,
178847 .elementwise_gpr,178857 .elementwise_gpr,
178848 .elementwise_sse,178858 .elementwise_sse,
178849 .xwordwise_sse,178859 .xwordwise_sse,
...@@ -179422,6 +179432,7 @@ fn genSetMem(...@@ -179422,6 +179432,7 @@ fn genSetMem(
179422 .unreach,179432 .unreach,
179423 .dead,179433 .dead,
179424 .indirect_load_frame,179434 .indirect_load_frame,
179435 .register_tee,
179425 .elementwise_gpr,179436 .elementwise_gpr,
179426 .elementwise_sse,179437 .elementwise_sse,
179427 .xwordwise_sse,179438 .xwordwise_sse,
...@@ -181569,142 +181580,139 @@ fn resolveCallingConventionValues(...@@ -181569,142 +181580,139 @@ fn resolveCallingConventionValues(
181569 .x86_64_win => result.stack_byte_count += @intCast(win64_shadow_space),181580 .x86_64_win => result.stack_byte_count += @intCast(win64_shadow_space),
181570 }181581 }
181571181582
181572 // Return values181583 result.return_value = switch (ret_ty.classify(zcu)) {
181573 if (ret_ty.isNoReturn(zcu)) {181584 .no_possible_value => .init(.unreach),
181574 result.return_value = .init(.unreach);181585 .one_possible_value => .init(.none),
181575 } else if (!ret_ty.hasRuntimeBits(zcu)) {181586 .runtime, .partially_comptime => return_value: {
181576 // TODO: is this even possible for C calling convention?181587 var ret_tracking: [4]InstTracking = undefined;
181577 result.return_value = .init(.none);181588 var ret_tracking_len: u32 = 0;
181578 } else {181589 var ret_gpr = abi.getCAbiIntReturnRegs(cc);
181579 var ret_tracking: [4]InstTracking = undefined;181590 var ret_sse = abi.getCAbiSseReturnRegs(cc);
181580 var ret_tracking_len: u32 = 0;181591 var ret_x87 = abi.getCAbiX87ReturnRegs(cc);
181581 var ret_gpr = abi.getCAbiIntReturnRegs(cc);181592
181582 var ret_sse = abi.getCAbiSseReturnRegs(cc);181593 var classes_buf: [8]abi.Class = undefined;
181583 var ret_x87 = abi.getCAbiX87ReturnRegs(cc);181594 const classes = classes: switch (cc) {
181584181595 else => unreachable,
181585 var classes_buf: [8]abi.Class = undefined;181596 .x86_64_sysv => {
181586 const classes = classes: switch (cc) {181597 classes_buf = abi.classifySystemV(ret_ty, zcu, cg.target, .ret);
181587 else => unreachable,181598 break :classes &classes_buf;
181588 .x86_64_sysv => {181599 },
181589 classes_buf = abi.classifySystemV(ret_ty, zcu, cg.target, .ret);181600 .x86_64_win => {
181590 break :classes std.mem.sliceTo(&classes_buf, .none);181601 classes_buf[0] = abi.classifyWindows(ret_ty, zcu, cg.target, .ret);
181591 },181602 break :classes classes_buf[0..1];
181592 .x86_64_win => {181603 },
181593 classes_buf[0] = abi.classifyWindows(ret_ty, zcu, cg.target, .ret);181604 };
181594 break :classes classes_buf[0..1];181605 for (classes) |class| switch (class) {
181595 },181606 .integer => {
181596 };181607 ret_tracking[ret_tracking_len] = .init(.{ .register = registerAlias(
181597 for (classes) |class| switch (class) {181608 ret_gpr[0],
181598 .integer => {181609 @intCast(@min(ret_ty.abiSize(zcu), 8)),
181599 ret_tracking[ret_tracking_len] = .init(.{ .register = registerAlias(181610 ) });
181600 ret_gpr[0],181611 ret_tracking_len += 1;
181601 @intCast(@min(ret_ty.abiSize(zcu), 8)),181612 ret_gpr = ret_gpr[1..];
181602 ) });181613 },
181603 ret_tracking_len += 1;181614 .sse, .float, .float_combine, .win_i128 => {
181604 ret_gpr = ret_gpr[1..];181615 ret_tracking[ret_tracking_len] = .init(.{
181605 },181616 .register = registerAlias(ret_sse[0], @intCast(ret_ty.abiSize(zcu))),
181606 .sse, .float, .float_combine, .win_i128 => {181617 });
181607 ret_tracking[ret_tracking_len] = .init(.{181618 ret_tracking_len += 1;
181608 .register = registerAlias(ret_sse[0], @intCast(ret_ty.abiSize(zcu))),181619 ret_sse = ret_sse[1..];
181609 });181620 },
181610 ret_tracking_len += 1;181621 .sseup => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.sse)),
181611 ret_sse = ret_sse[1..];181622 .x87 => {
181612 },181623 ret_tracking[ret_tracking_len] = .init(.{ .register = ret_x87[0] });
181613 .sseup => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.sse)),181624 ret_tracking_len += 1;
181614 .x87 => {181625 ret_x87 = ret_x87[1..];
181615 ret_tracking[ret_tracking_len] = .init(.{ .register = ret_x87[0] });181626 },
181616 ret_tracking_len += 1;181627 .x87up => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.x87)),
181617 ret_x87 = ret_x87[1..];181628 .none => {},
181618 },181629 .memory => {
181619 .x87up => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.x87)),181630 ret_tracking[ret_tracking_len] = .{
181620 .none => unreachable,181631 .short = .{ .indirect = .{ .reg = ret_gpr[0].to64() } },
181621 .memory => {181632 .long = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } },
181622 ret_tracking[ret_tracking_len] = .{181633 };
181623 .short = .{ .indirect = .{ .reg = ret_gpr[0].to64() } },181634 ret_tracking_len += 1;
181624 .long = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } },181635 ret_gpr = ret_gpr[1..];
181625 };181636 param_gpr_index += 1;
181626 ret_tracking_len += 1;181637 },
181627 ret_gpr = ret_gpr[1..];181638 .integer_per_element => {
181628 param_gpr_index += 1;181639 const len: u32 = @intCast(ret_ty.vectorLen(zcu));
181629 },181640 const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8));
181630 .integer_per_element => {181641 for (ret_tracking[ret_tracking_len..][0..len], ret_gpr[0..len]) |*tracking, gpr|
181631 const len: u32 = @intCast(ret_ty.vectorLen(zcu));181642 tracking.* = .init(.{ .register = registerAlias(gpr, alias_size) });
181632 const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8));181643 ret_tracking_len += len;
181633 for (ret_tracking[ret_tracking_len..][0..len], ret_gpr[0..len]) |*tracking, gpr|181644 ret_gpr = ret_gpr[len..];
181634 tracking.* = .init(.{ .register = registerAlias(gpr, alias_size) });181645 },
181635 ret_tracking_len += len;181646 .sse_per_element => {
181636 ret_gpr = ret_gpr[len..];181647 const len: u32 = @intCast(ret_ty.vectorLen(zcu));
181637 },181648 const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8));
181638 .sse_per_element => {181649 for (ret_tracking[ret_tracking_len..][0..len], ret_sse[0..len]) |*tracking, sse|
181639 const len: u32 = @intCast(ret_ty.vectorLen(zcu));181650 tracking.* = .init(.{ .register = registerAlias(sse, alias_size) });
181640 const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8));181651 ret_tracking_len += len;
181641 for (ret_tracking[ret_tracking_len..][0..len], ret_sse[0..len]) |*tracking, sse|181652 ret_sse = ret_sse[len..];
181642 tracking.* = .init(.{ .register = registerAlias(sse, alias_size) });181653 },
181643 ret_tracking_len += len;181654 .sse_sse_x87_per_qword, .sse_per_xword, .sse_per_yword, .sse_per_zword => {
181644 ret_sse = ret_sse[len..];181655 const reg_size: u32 = switch (class) {
181645 },
181646 .sse_sse_x87_per_qword, .sse_per_xword, .sse_per_yword, .sse_per_zword => {
181647 const reg_size: u32 = switch (class) {
181648 else => unreachable,
181649 .sse_sse_x87_per_qword => 8,
181650 .sse_per_xword => 16,
181651 .sse_per_yword => 32,
181652 .sse_per_zword => 64,
181653 };
181654 var byte_offset: u32 = 0;
181655 const unaligned_size = cg.unalignedSize(ret_ty);
181656 while (byte_offset < unaligned_size) : (byte_offset += reg_size) {
181657 switch (@as(enum { sse, x87 }, switch (class) {
181658 else => unreachable,181656 else => unreachable,
181659 .sse_sse_x87_per_qword => switch (byte_offset) {181657 .sse_sse_x87_per_qword => 8,
181660 0 => .sse, // duck181658 .sse_per_xword => 16,
181661 8 => .sse, // duck181659 .sse_per_yword => 32,
181662 else => .x87, // goose!181660 .sse_per_zword => 64,
181663 },181661 };
181664 .sse_per_xword, .sse_per_yword, .sse_per_zword => .sse,181662 var byte_offset: u32 = 0;
181665 })) {181663 const unaligned_size = cg.unalignedSize(ret_ty);
181666 .sse => {181664 while (byte_offset < unaligned_size) : (byte_offset += reg_size) {
181667 ret_tracking[ret_tracking_len] = .init(.{181665 switch (@as(enum { sse, x87 }, switch (class) {
181668 .register = registerAlias(ret_sse[0], reg_size),181666 else => unreachable,
181669 });181667 .sse_sse_x87_per_qword => switch (byte_offset) {
181670 ret_tracking_len += 1;181668 0 => .sse, // duck
181671 ret_sse = ret_sse[1..];181669 8 => .sse, // duck
181672 },181670 else => .x87, // goose!
181673 .x87 => {181671 },
181674 ret_tracking[ret_tracking_len] = .init(.{181672 .sse_per_xword, .sse_per_yword, .sse_per_zword => .sse,
181675 .register = registerAlias(ret_x87[0], reg_size),181673 })) {
181676 });181674 .sse => {
181677 ret_tracking_len += 1;181675 ret_tracking[ret_tracking_len] = .init(.{
181678 ret_x87 = ret_x87[1..];181676 .register = registerAlias(ret_sse[0], reg_size),
181679 },181677 });
181678 ret_tracking_len += 1;
181679 ret_sse = ret_sse[1..];
181680 },
181681 .x87 => {
181682 ret_tracking[ret_tracking_len] = .init(.{
181683 .register = registerAlias(ret_x87[0], reg_size),
181684 });
181685 ret_tracking_len += 1;
181686 ret_x87 = ret_x87[1..];
181687 },
181688 }
181680 }181689 }
181681 }181690 },
181682 },181691 };
181683 };181692 break :return_value switch (ret_tracking_len) {
181684 result.return_value = switch (ret_tracking_len) {181693 else => unreachable,
181685 else => unreachable,181694 1 => ret_tracking[0],
181686 1 => ret_tracking[0],181695 2 => .init(.{ .register_pair = .{
181687 2 => .init(.{ .register_pair = .{181696 ret_tracking[0].short.register,
181688 ret_tracking[0].short.register,181697 ret_tracking[1].short.register,
181689 ret_tracking[1].short.register,181698 } }),
181690 } }),181699 3 => .init(.{ .register_triple = .{
181691 3 => .init(.{ .register_triple = .{181700 ret_tracking[0].short.register,
181692 ret_tracking[0].short.register,181701 ret_tracking[1].short.register,
181693 ret_tracking[1].short.register,181702 ret_tracking[2].short.register,
181694 ret_tracking[2].short.register,181703 } }),
181695 } }),181704 4 => .init(.{ .register_quadruple = .{
181696 4 => .init(.{ .register_quadruple = .{181705 ret_tracking[0].short.register,
181697 ret_tracking[0].short.register,181706 ret_tracking[1].short.register,
181698 ret_tracking[1].short.register,181707 ret_tracking[2].short.register,
181699 ret_tracking[2].short.register,181708 ret_tracking[3].short.register,
181700 ret_tracking[3].short.register,181709 } }),
181701 } }),181710 };
181702 };181711 },
181703 }181712 .fully_comptime => unreachable,
181713 };
181704181714
181705 // Input params181715 params: for (0.., param_types, result.args) |param_index, ty, *arg| {
181706 params: for (param_types, result.args) |ty, *arg| {
181707 assert(ty.hasRuntimeBits(zcu));
181708 result.air_arg_count += 1;181716 result.air_arg_count += 1;
181709 switch (cc) {181717 switch (cc) {
181710 else => unreachable,181718 else => unreachable,
...@@ -181726,7 +181734,7 @@ fn resolveCallingConventionValues(...@@ -181726,7 +181734,7 @@ fn resolveCallingConventionValues(
181726 else => unreachable,181734 else => unreachable,
181727 .x86_64_sysv => {181735 .x86_64_sysv => {
181728 classes_buf = abi.classifySystemV(ty, zcu, cg.target, .arg);181736 classes_buf = abi.classifySystemV(ty, zcu, cg.target, .arg);
181729 break :classes std.mem.sliceTo(&classes_buf, .none);181737 break :classes &classes_buf;
181730 },181738 },
181731 .x86_64_win => {181739 .x86_64_win => {
181732 classes_buf[0] = abi.classifyWindows(ty, zcu, cg.target, .arg);181740 classes_buf[0] = abi.classifyWindows(ty, zcu, cg.target, .arg);
...@@ -181749,12 +181757,28 @@ fn resolveCallingConventionValues(...@@ -181749,12 +181757,28 @@ fn resolveCallingConventionValues(
181749 var byte_offset: u32 = 0;181757 var byte_offset: u32 = 0;
181750 while (byte_offset < abi_size) : (byte_offset += reg_size) {181758 while (byte_offset < abi_size) : (byte_offset += reg_size) {
181751 if (param_sse_index >= param_sse.len) break :classes;181759 if (param_sse_index >= param_sse.len) break :classes;
181752181760 arg_mcv[arg_mcv_len] = arg_mcv: {
181753 const param_sse_reg = registerAlias(param_sse[param_sse_index], reg_size);181761 const param_sse_reg =
181754 param_sse_index += 1;181762 registerAlias(param_sse[param_sse_index], reg_size);
181755181763 switch (cc) {
181756 arg_mcv[arg_mcv_len] = .{ .register = param_sse_reg };181764 else => unreachable,
181765 .x86_64_sysv => {},
181766 .x86_64_win => if (param_index >= fn_info.param_types.len) {
181767 const param_gpr_reg =
181768 registerAlias(param_gpr[param_gpr_index], reg_size);
181769 param_gpr_index += 1;
181770 break :arg_mcv .{ .register_tee = .{
181771 param_sse_reg,
181772 param_gpr_reg,
181773 .none,
181774 .none,
181775 } };
181776 },
181777 }
181778 break :arg_mcv .{ .register = param_sse_reg };
181779 };
181757 arg_mcv_len += 1;181780 arg_mcv_len += 1;
181781 param_sse_index += 1;
181758 }181782 }
181759 },181783 },
181760 .sseup => assert(arg_mcv[arg_mcv_len - 1].register.isClass(.sse)),181784 .sseup => assert(arg_mcv[arg_mcv_len - 1].register.isClass(.sse)),
...@@ -181764,13 +181788,16 @@ fn resolveCallingConventionValues(...@@ -181764,13 +181788,16 @@ fn resolveCallingConventionValues(
181764 .x87, .x87up, .memory => break,181788 .x87, .x87up, .memory => break,
181765 },181789 },
181766 .x86_64_win => if (param_gpr_index < param_gpr.len) {181790 .x86_64_win => if (param_gpr_index < param_gpr.len) {
181767 arg_mcv[arg_mcv_len] = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } };181791 arg_mcv[arg_mcv_len] = .{ .indirect = .{
181792 .reg = param_gpr[param_gpr_index].to64(),
181793 } };
181768 arg_mcv_len += 1;181794 arg_mcv_len += 1;
181769 param_gpr_index += 1;181795 param_gpr_index += 1;
181770 } else {181796 } else {
181771 assert(arg_mcv_len == 0);181797 assert(arg_mcv_len == 0);
181772 const param_align = Type.usize.abiAlignment(zcu);181798 const param_align = Type.usize.abiAlignment(zcu);
181773 result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count));181799 result.stack_byte_count =
181800 @intCast(param_align.forward(result.stack_byte_count));
181774 result.stack_align = result.stack_align.max(param_align);181801 result.stack_align = result.stack_align.max(param_align);
181775 arg.* = .{ .indirect_load_frame = .{181802 arg.* = .{ .indirect_load_frame = .{
181776 .index = stack_frame_base,181803 .index = stack_frame_base,
...@@ -181781,7 +181808,7 @@ fn resolveCallingConventionValues(...@@ -181781,7 +181808,7 @@ fn resolveCallingConventionValues(
181781 },181808 },
181782 else => unreachable,181809 else => unreachable,
181783 },181810 },
181784 .none => unreachable,181811 .none => {},
181785 .integer_per_element,181812 .integer_per_element,
181786 .sse_per_element,181813 .sse_per_element,
181787 .sse_per_xword,181814 .sse_per_xword,
...@@ -181850,6 +181877,7 @@ fn resolveCallingConventionValues(...@@ -181850,6 +181877,7 @@ fn resolveCallingConventionValues(
181850 } else {181877 } else {
181851 arg.* = switch (arg_mcv_len) {181878 arg.* = switch (arg_mcv_len) {
181852 else => unreachable,181879 else => unreachable,
181880 0 => .none,
181853 1 => arg_mcv[0],181881 1 => arg_mcv[0],
181854 2 => .{ .register_pair = .{181882 2 => .{ .register_pair = .{
181855 arg_mcv[0].register,181883 arg_mcv[0].register,
...@@ -181899,82 +181927,82 @@ fn resolveCallingConventionValues(...@@ -181899,82 +181927,82 @@ fn resolveCallingConventionValues(
181899 param_gpr = param_gpr[0 .. param_gpr.len - 1];181927 param_gpr = param_gpr[0 .. param_gpr.len - 1];
181900 }181928 }
181901181929
181902 // Return values181930 result.return_value = switch (ret_ty.classify(zcu)) {
181903 result.return_value = if (ret_ty.isNoReturn(zcu))181931 .no_possible_value => .init(.unreach),
181904 .init(.unreach)181932 .one_possible_value => .init(.none),
181905 else if (!ret_ty.hasRuntimeBits(zcu))181933 .runtime, .partially_comptime => return_value: {
181906 .init(.none)181934 const ret_gpr = abi.getCAbiIntReturnRegs(cc);
181907 else return_value: {181935 const ret_size: u31 = @intCast(ret_ty.abiSize(zcu));
181908 const ret_gpr = abi.getCAbiIntReturnRegs(cc);181936 if (abi.zigcc.return_in_regs) switch (cg.regClassForType(ret_ty)) {
181909 const ret_size: u31 = @intCast(ret_ty.abiSize(zcu));181937 .general_purpose, .gphi => if (ret_size <= @as(u4, switch (cg.target.cpu.arch) {
181910 if (abi.zigcc.return_in_regs) switch (cg.regClassForType(ret_ty)) {181938 else => unreachable,
181911 .general_purpose, .gphi => if (ret_size <= @as(u4, switch (cg.target.cpu.arch) {181939 .x86 => 4,
181912 else => unreachable,181940 .x86_64 => 8,
181913 .x86 => 4,181941 }))
181914 .x86_64 => 8,181942 break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) })
181915 }))181943 else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu))
181916 break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) })181944 break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }),
181917 else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu))181945 .segment, .mmx, .ip, .cr, .dr => unreachable,
181918 break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }),181946 .x87 => if (ret_size <= 16) break :return_value .init(.{ .register = .st0 }),
181919 .segment, .mmx, .ip, .cr, .dr => unreachable,181947 .sse => if (ret_size <= cg.vectorSize(.float)) break :return_value .init(.{
181920 .x87 => if (ret_size <= 16) break :return_value .init(.{ .register = .st0 }),181948 .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)),
181921 .sse => if (ret_size <= cg.vectorSize(.float)) break :return_value .init(.{181949 }),
181922 .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)),181950 };
181923 }),181951 const ret_indirect_reg = param_gpr[0];
181924 };181952 param_gpr = param_gpr[1..];
181925 const ret_indirect_reg = param_gpr[0];181953 break :return_value .{
181926 param_gpr = param_gpr[1..];181954 .short = .{ .indirect = .{ .reg = ret_gpr[0] } },
181927 break :return_value .{181955 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
181928 .short = .{ .indirect = .{ .reg = ret_gpr[0] } },181956 };
181929 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },181957 },
181930 };181958 .fully_comptime => unreachable,
181931 };181959 };
181932181960
181933 // Input params181961 for (param_types, result.args) |param_ty, *arg| switch (param_ty.classify(zcu)) {
181934 for (param_types, result.args) |param_ty, *arg| {181962 .no_possible_value => arg.* = .unreach,
181935 if (!param_ty.hasRuntimeBits(zcu)) {181963 .one_possible_value => arg.* = .none,
181936 arg.* = .none;181964 .runtime, .partially_comptime => {
181937 continue;181965 result.air_arg_count += 1;
181938 }181966 const param_size: u31 = @intCast(param_ty.abiSize(zcu));
181939 result.air_arg_count += 1;181967 if (abi.zigcc.params_in_regs) switch (cg.regClassForType(param_ty)) {
181940 const param_size: u31 = @intCast(param_ty.abiSize(zcu));181968 .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (cg.target.cpu.arch) {
181941 if (abi.zigcc.params_in_regs) switch (cg.regClassForType(param_ty)) {181969 else => unreachable,
181942 .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (cg.target.cpu.arch) {181970 .x86 => 4,
181943 else => unreachable,181971 .x86_64 => 8,
181944 .x86 => 4,181972 })) {
181945 .x86_64 => 8,181973 arg.* = .{ .register = registerAlias(param_gpr[0], param_size) };
181946 })) {181974 param_gpr = param_gpr[1..];
181947 arg.* = .{ .register = registerAlias(param_gpr[0], param_size) };181975 continue;
181948 param_gpr = param_gpr[1..];181976 } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) {
181949 continue;181977 arg.* = .{ .register_pair = param_gpr[0..2].* };
181950 } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) {181978 param_gpr = param_gpr[2..];
181951 arg.* = .{ .register_pair = param_gpr[0..2].* };181979 continue;
181952 param_gpr = param_gpr[2..];181980 },
181953 continue;181981 .segment, .mmx, .ip, .cr, .dr => unreachable,
181954 },181982 .x87 => if (param_x87.len >= 1 and param_size <= 16) {
181955 .segment, .mmx, .ip, .cr, .dr => unreachable,181983 arg.* = .{ .register = param_x87[0] };
181956 .x87 => if (param_x87.len >= 1 and param_size <= 16) {181984 param_x87 = param_x87[1..];
181957 arg.* = .{ .register = param_x87[0] };181985 continue;
181958 param_x87 = param_x87[1..];181986 },
181959 continue;181987 .sse => if (param_sse.len >= 1 and param_size <= cg.vectorSize(.float)) {
181960 },181988 arg.* = .{
181961 .sse => if (param_sse.len >= 1 and param_size <= cg.vectorSize(.float)) {181989 .register = registerAlias(param_sse[0], @max(param_size, 16)),
181962 arg.* = .{181990 };
181963 .register = registerAlias(param_sse[0], @max(param_size, 16)),181991 param_sse = param_sse[1..];
181964 };181992 continue;
181965 param_sse = param_sse[1..];181993 },
181966 continue;181994 };
181967 },181995 const param_align = param_ty.abiAlignment(zcu);
181968 };181996 result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count));
181969 const param_align = param_ty.abiAlignment(zcu);181997 result.stack_align = result.stack_align.max(param_align);
181970 result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count));181998 arg.* = .{ .load_frame = .{
181971 result.stack_align = result.stack_align.max(param_align);181999 .index = stack_frame_base,
181972 arg.* = .{ .load_frame = .{182000 .off = result.stack_byte_count,
181973 .index = stack_frame_base,182001 } };
181974 .off = result.stack_byte_count,182002 result.stack_byte_count += param_size;
181975 } };182003 },
181976 result.stack_byte_count += param_size;182004 .fully_comptime => unreachable,
181977 }182005 };
181978 },182006 },
181979 else => return cg.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),182007 else => return cg.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),
181980 }182008 }
...@@ -182241,13 +182269,11 @@ fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type {...@@ -182241,13 +182269,11 @@ fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type {
182241 return Temp.typeOf(.{ .index = inst }, self);182269 return Temp.typeOf(.{ .index = inst }, self);
182242}182270}
182243182271
182244fn promoteInt(self: *CodeGen, ty: Type) Type {182272fn promoteInt(cg: *CodeGen, ty: Type) Type {
182245 const pt = self.pt;182273 const pt = cg.pt;
182246 const zcu = pt.zcu;182274 const zcu = pt.zcu;
182247 const int_info: InternPool.Key.IntType = switch (ty.toIntern()) {182275 const int_info = cg.intInfo(ty) orelse return ty;
182248 .bool_type => .{ .signedness = .unsigned, .bits = 1 },182276 if (int_info.bits == 0) return .void;
182249 else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return ty,
182250 };
182251 for ([_]Type{182277 for ([_]Type{
182252 .c_int, .c_uint,182278 .c_int, .c_uint,
182253 .c_long, .c_ulong,182279 .c_long, .c_ulong,
...@@ -182424,6 +182450,7 @@ const Temp = struct {...@@ -182424,6 +182450,7 @@ const Temp = struct {
182424 .lea_lazy_sym,182450 .lea_lazy_sym,
182425 .lea_extern_func,182451 .lea_extern_func,
182426 .load_extern_func,182452 .load_extern_func,
182453 .register_tee,
182427 .elementwise_gpr,182454 .elementwise_gpr,
182428 .elementwise_sse,182455 .elementwise_sse,
182429 .xwordwise_sse,182456 .xwordwise_sse,
...@@ -182891,6 +182918,7 @@ const Temp = struct {...@@ -182891,6 +182918,7 @@ const Temp = struct {
182891 .register_overflow,182918 .register_overflow,
182892 .register_mask,182919 .register_mask,
182893 .indirect_load_frame,182920 .indirect_load_frame,
182921 .register_tee,
182894 .elementwise_gpr,182922 .elementwise_gpr,
182895 .elementwise_sse,182923 .elementwise_sse,
182896 .xwordwise_sse,182924 .xwordwise_sse,
...@@ -188002,6 +188030,7 @@ const Temp = struct {...@@ -188002,6 +188030,7 @@ const Temp = struct {
188002 .unreach,188030 .unreach,
188003 .dead,188031 .dead,
188004 .indirect_load_frame,188032 .indirect_load_frame,
188033 .register_tee,
188005 .elementwise_gpr,188034 .elementwise_gpr,
188006 .elementwise_sse,188035 .elementwise_sse,
188007 .xwordwise_sse,188036 .xwordwise_sse,
...@@ -190673,6 +190702,7 @@ const Select = struct {...@@ -190673,6 +190702,7 @@ const Select = struct {
190673 .lea_extern_func => |extern_func| .{ .imm = .{ .extern_func = extern_func } },190702 .lea_extern_func => |extern_func| .{ .imm = .{ .extern_func = extern_func } },
190674 else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.flags.base.size }) },190703 else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.flags.base.size }) },
190675 .lea_frame,190704 .lea_frame,
190705 .register_tee,
190676 .elementwise_gpr,190706 .elementwise_gpr,
190677 .elementwise_sse,190707 .elementwise_sse,
190678 .xwordwise_sse,190708 .xwordwise_sse,
src/codegen/x86_64/abi.zig+18-10
...@@ -37,6 +37,8 @@ pub const Class = enum {...@@ -37,6 +37,8 @@ pub const Class = enum {
37 /// Clang passes each 64 bytes in a separate `Class.sse`.37 /// Clang passes each 64 bytes in a separate `Class.sse`.
38 sse_per_zword,38 sse_per_zword,
3939
40 pub const zero_bit: [8]Class = .{ .none, .none, .none, .none, .none, .none, .none, .none };
41
40 pub const one_integer: [8]Class = .{ .integer, .none, .none, .none, .none, .none, .none, .none };42 pub const one_integer: [8]Class = .{ .integer, .none, .none, .none, .none, .none, .none, .none };
41 pub const two_integers: [8]Class = .{ .integer, .integer, .none, .none, .none, .none, .none, .none };43 pub const two_integers: [8]Class = .{ .integer, .integer, .none, .none, .none, .none, .none, .none };
42 pub const three_integers: [8]Class = .{ .integer, .integer, .integer, .none, .none, .none, .none, .none };44 pub const three_integers: [8]Class = .{ .integer, .integer, .integer, .none, .none, .none, .none, .none };
...@@ -100,12 +102,11 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -100,12 +102,11 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
100 // as if they were integers of the same size."102 // as if they were integers of the same size."
101 var ty = init_ty;103 var ty = init_ty;
102 while (true) return switch (ty.zigTypeTag(zcu)) {104 while (true) return switch (ty.zigTypeTag(zcu)) {
105 .void => return .none,
106 .bool,
103 .pointer,107 .pointer,
104 .int,108 .int,
105 .bool,
106 .@"enum",109 .@"enum",
107 .void,
108 .noreturn,
109 .error_set,110 .error_set,
110 .@"struct",111 .@"struct",
111 .@"union",112 .@"union",
...@@ -115,7 +116,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -115,7 +116,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
115 .@"anyframe",116 .@"anyframe",
116 .frame,117 .frame,
117 => switch (ty.abiSize(zcu)) {118 => switch (ty.abiSize(zcu)) {
118 0 => unreachable,119 0 => .none,
119 1, 2, 4, 8 => .integer,120 1, 2, 4, 8 => .integer,
120 else => switch (ty.zigTypeTag(zcu)) {121 else => switch (ty.zigTypeTag(zcu)) {
121 .int => .win_i128,122 .int => .win_i128,
...@@ -126,6 +127,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -126,6 +127,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
126 else => .memory,127 else => .memory,
127 },128 },
128 },129 },
130 .noreturn => unreachable,
129 .float => switch (ty.floatBits(target)) {131 .float => switch (ty.floatBits(target)) {
130 16, 32, 64 => .sse,132 16, 32, 64 => .sse,
131 80 => .memory,133 80 => .memory,
...@@ -134,6 +136,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -134,6 +136,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
134 },136 },
135 .vector => {137 .vector => {
136 const len = ty.vectorLen(zcu);138 const len = ty.vectorLen(zcu);
139 if (len == 0) return .none;
137 const elem_ty = ty.childType(zcu);140 const elem_ty = ty.childType(zcu);
138 if (len == 1) {141 if (len == 1) {
139 ty = elem_ty;142 ty = elem_ty;
...@@ -178,19 +181,18 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -178,19 +181,18 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
178/// the beginning of the array; unused slots are filled with .none.181/// the beginning of the array; unused slots are filled with .none.
179pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) [8]Class {182pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) [8]Class {
180 switch (ty.zigTypeTag(zcu)) {183 switch (ty.zigTypeTag(zcu)) {
181 .pointer => switch (ty.ptrSize(zcu)) {184 .void => return Class.zero_bit,
182 .slice => return Class.two_integers,185 .bool => return Class.one_integer,
183 else => return Class.one_integer,186 .noreturn => unreachable,
184 },
185 .int, .@"enum", .error_set => {187 .int, .@"enum", .error_set => {
186 const bits = ty.intInfo(zcu).bits;188 const bits = ty.intInfo(zcu).bits;
189 if (bits == 0) return Class.zero_bit;
187 if (bits <= 64 * 1) return Class.one_integer;190 if (bits <= 64 * 1) return Class.one_integer;
188 if (bits <= 64 * 2) return Class.two_integers;191 if (bits <= 64 * 2) return Class.two_integers;
189 if (bits <= 64 * 3) return Class.three_integers;192 if (bits <= 64 * 3) return Class.three_integers;
190 if (bits <= 64 * 4) return Class.four_integers;193 if (bits <= 64 * 4) return Class.four_integers;
191 return Class.stack;194 return Class.stack;
192 },195 },
193 .bool, .void, .noreturn => return Class.one_integer,
194 .float => switch (ty.floatBits(target)) {196 .float => switch (ty.floatBits(target)) {
195 16 => {197 16 => {
196 if (ctx == .other) return Class.stack;198 if (ctx == .other) return Class.stack;
...@@ -209,9 +211,13 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont...@@ -209,9 +211,13 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont
209 80 => return Class.f80,211 80 => return Class.f80,
210 else => unreachable,212 else => unreachable,
211 },213 },
214 .pointer => switch (ty.ptrSize(zcu)) {
215 .slice => return Class.two_integers,
216 else => return Class.one_integer,
217 },
212 .vector => {218 .vector => {
213 const len = ty.vectorLen(zcu);219 const len = ty.vectorLen(zcu);
214 if (len == 0) return Class.one_integer;220 if (len == 0) return Class.zero_bit;
215 const elem_ty = ty.childType(zcu);221 const elem_ty = ty.childType(zcu);
216 if (elem_ty.toIntern() == .bool_type) {222 if (elem_ty.toIntern() == .bool_type) {
217 if (len <= 32) return Class.one_integer;223 if (len <= 32) return Class.one_integer;
...@@ -275,6 +281,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont...@@ -275,6 +281,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont
275 // "If the size of the aggregate exceeds a single eightbyte, each is classified281 // "If the size of the aggregate exceeds a single eightbyte, each is classified
276 // separately.".282 // separately.".
277 const ty_size = ty.abiSize(zcu);283 const ty_size = ty.abiSize(zcu);
284 if (ty_size == 0) return Class.zero_bit;
278 switch (ty.containerLayout(zcu)) {285 switch (ty.containerLayout(zcu)) {
279 .auto => unreachable,286 .auto => unreachable,
280 .@"extern" => {},287 .@"extern" => {},
...@@ -325,6 +332,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont...@@ -325,6 +332,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont
325 },332 },
326 .array => {333 .array => {
327 const ty_size = ty.abiSize(zcu);334 const ty_size = ty.abiSize(zcu);
335 if (ty_size == 0) return Class.zero_bit;
328 if (ty_size <= 8) return Class.one_integer;336 if (ty_size <= 8) return Class.one_integer;
329 if (ty_size <= 16) return Class.two_integers;337 if (ty_size <= 16) return Class.two_integers;
330 return Class.stack;338 return Class.stack;
test/c_abi/cfuncs.c+15
...@@ -16211,3 +16211,18 @@ void __attribute__((vectorcall)) c_vectorcall_check(int a, float b, double c, vo...@@ -16211,3 +16211,18 @@ void __attribute__((vectorcall)) c_vectorcall_check(int a, float b, double c, vo
16211 zig_vectorcall_check(a, b, c, d, e, f, g, h, i, j);16211 zig_vectorcall_check(a, b, c, d, e, f, g, h, i, j);
16212}16212}
16213#endif16213#endif
16214
16215#if defined(__x86_64__) && defined(_WIN64)
16216void c_win64_varargs_u64_f64_u64_f64(uint64_t a, double b, uint64_t c, double d) {
16217 assert_or_panic(a == UINT64_C(0x3ff0000000000000));
16218 assert_or_panic(b == 2.0);
16219 assert_or_panic(c == UINT64_C(0x4008000000000000));
16220 assert_or_panic(d == 4.0);
16221}
16222void c_win64_varargs_f64_u64_f64_u64(double a, uint64_t b, double c, uint64_t d) {
16223 assert_or_panic(a == 5.0);
16224 assert_or_panic(b == UINT64_C(0x4018000000000000));
16225 assert_or_panic(c == 7.0);
16226 assert_or_panic(d == UINT64_C(0x4020000000000000));
16227}
16228#endif
test/c_abi/main.zig+33-6
...@@ -17140,9 +17140,7 @@ test "byval tail callsite attribute" {...@@ -17140,9 +17140,7 @@ test "byval tail callsite attribute" {
17140}17140}
1714117141
17142test "x86 fastcall calling convention" {17142test "x86 fastcall calling convention" {
17143 if (builtin.cpu.arch != .x86) return error.SkipZigTest;17143 if (builtin.cpu.arch != .x86 or builtin.os.tag != .windows or builtin.abi != .msvc) return error.SkipZigTest;
17144 if (builtin.os.tag != .windows) return error.SkipZigTest;
17145 if (builtin.abi != .msvc) return error.SkipZigTest;
1714617144
17147 const static = struct {17145 const static = struct {
17148 const fastcall: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };17146 const fastcall: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
...@@ -17252,9 +17250,7 @@ test "x86 fastcall calling convention" {...@@ -17252,9 +17250,7 @@ test "x86 fastcall calling convention" {
17252}17250}
1725317251
17254test "x86 vectorcall calling convention" {17252test "x86 vectorcall calling convention" {
17255 if (builtin.cpu.arch != .x86) return error.SkipZigTest;17253 if (builtin.cpu.arch != .x86 or builtin.os.tag != .windows or builtin.abi != .msvc) return error.SkipZigTest;
17256 if (builtin.os.tag != .windows) return error.SkipZigTest;
17257 if (builtin.abi != .msvc) return error.SkipZigTest;
1725817254
17259 const static = struct {17255 const static = struct {
17260 extern fn c_vectorcall_check(a: c_int, b: f32, c: f64, d: *anyopaque, e: f32, f: f64, g: f64, h: f32, i: f32, j: c_int) callconv(.{ .x86_vectorcall = .{} }) void;17256 extern fn c_vectorcall_check(a: c_int, b: f32, c: f64, d: *anyopaque, e: f32, f: f64, g: f64, h: f32, i: f32, j: c_int) callconv(.{ .x86_vectorcall = .{} }) void;
...@@ -17273,3 +17269,34 @@ test "x86 vectorcall calling convention" {...@@ -17273,3 +17269,34 @@ test "x86 vectorcall calling convention" {
17273 };17269 };
17274 static.c_vectorcall_check(1, 2.0, 3.0, @ptrFromInt(4), 5.0, 6.0, 7.0, 8.0, 9.0, 10);17270 static.c_vectorcall_check(1, 2.0, 3.0, @ptrFromInt(4), 5.0, 6.0, 7.0, 8.0, 9.0, 10);
17275}17271}
17272
17273extern fn c_win64_varargs_u64_f64_u64_f64(...) void;
17274extern fn c_win64_varargs_f64_u64_f64_u64(...) void;
17275
17276test "win64 varargs" {
17277 if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .windows) return error.SkipZigTest;
17278
17279 const Opv = extern struct {};
17280 c_win64_varargs_u64_f64_u64_f64(
17281 @as(Opv, .{}),
17282 @as(f32, 1),
17283 @as(Opv, .{}),
17284 @as(f32, 2.0),
17285 @as(Opv, .{}),
17286 @as(f64, 3),
17287 @as(Opv, .{}),
17288 @as(f64, 4.0),
17289 @as(Opv, .{}),
17290 );
17291 c_win64_varargs_f64_u64_f64_u64(
17292 @as(Opv, .{}),
17293 @as(f32, 5),
17294 @as(Opv, .{}),
17295 @as(f32, 6.0),
17296 @as(Opv, .{}),
17297 @as(f64, 7),
17298 @as(Opv, .{}),
17299 @as(f64, 8.0),
17300 @as(Opv, .{}),
17301 );
17302}