authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-18 22:04:34+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-18 22:04:34+02:00
log806624169a70301f37b6fe4dbdc5b6827cfd1ab1
tree2d2b700a60ad21c1a3ea5650c80ac5d122745675
parent3f9fe9e28f83119f8ecf2fdafcd12967417634e9
parentcc9447c103a540ae21582385ef33581c9719324e

Merge pull request 'x86_64: fixes' (#36860) from jacobly/x86_64-opv-arg into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36860 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

7 files changed, 168 insertions(+), 110 deletions(-)

src/codegen/x86_64/CodeGen.zig+86-89
......@@ -1224,9 +1224,7 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {
12241224 .pseudo_dbg_enter_block_none,
12251225 .pseudo_dbg_leave_block_none,
12261226 .pseudo_dbg_end_none,
1227 .pseudo_dbg_arg_none,
12281227 .pseudo_dbg_var_args_none,
1229 .pseudo_dbg_var_none,
12301228 .pseudo_dead_none,
12311229 => {},
12321230 .pseudo_dbg_line_stmt_line_column,
......@@ -2318,39 +2316,32 @@ fn genMainBody(
23182316 };
23192317 defer zir_param_index += 1;
23202318
2321 if (comptime_args.len > 0) switch (comptime_args.get(ip)[zir_param_index]) {
2322 .none => {},
2323 else => |comptime_arg| {
2324 try cg.mir_locals.append(cg.gpa, .{ .name = name, .type = ip.typeOf(comptime_arg) });
2325 _ = try cg.addInst(.{
2326 .tag = .pseudo,
2327 .ops = .pseudo_dbg_arg_val,
2328 .data = .{ .ip_index = comptime_arg },
2329 });
2330 continue;
2319 const arg_ty: Type, const arg_val: ?Value = arg: switch (if (comptime_args.len > 0)
2320 comptime_args.get(ip)[zir_param_index]
2321 else
2322 .none) {
2323 else => |arg_val| .{ .fromInterned(ip.typeOf(arg_val)), .fromInterned(arg_val) },
2324 .none => {
2325 const arg_ty: Type = .fromInterned(fn_info.param_types.get(ip)[fn_param_index]);
2326 fn_param_index += 1;
2327 break :arg .{ arg_ty, try arg_ty.onePossibleValue(pt) };
23312328 },
23322329 };
2333
2334 const arg_ty = fn_info.param_types.get(ip)[fn_param_index];
2335 try cg.mir_locals.append(cg.gpa, .{ .name = name, .type = arg_ty });
2336 fn_param_index += 1;
2337
2338 if (air_arg_index == air_args_body.len) {
2339 try cg.asmPseudo(.pseudo_dbg_arg_none);
2330 try cg.mir_locals.append(cg.gpa, .{ .name = name, .type = arg_ty.toIntern() });
2331 if (arg_val) |val| {
2332 _ = try cg.addInst(.{
2333 .tag = .pseudo,
2334 .ops = .pseudo_dbg_arg_val,
2335 .data = .{ .ip_index = val.toIntern() },
2336 });
23402337 continue;
23412338 }
2339
23422340 const air_arg_inst = air_args_body[air_arg_index];
23432341 const air_arg_data = cg.air.instructions.items(.data)[air_arg_index].arg;
2344 if (air_arg_data.zir_param_index != zir_param_index) {
2345 try cg.asmPseudo(.pseudo_dbg_arg_none);
2346 continue;
2347 }
23482342 air_arg_index += 1;
2349 try cg.genLocalDebugInfo(
2350 .arg,
2351 .fromInterned(arg_ty),
2352 cg.getResolvedInstValue(air_arg_inst).short,
2353 );
2343 assert(air_arg_data.zir_param_index == zir_param_index);
2344 try cg.genLocalDebugInfo(.arg, arg_ty, cg.getResolvedInstValue(air_arg_inst).short);
23542345 }
23552346 if (fn_info.is_var_args) try cg.asmPseudo(.pseudo_dbg_var_args_none);
23562347 }
......@@ -180623,6 +180614,7 @@ fn airAtomicStore(self: *CodeGen, inst: Air.Inst.Index, order: std.lang.AtomicOr
180623180614fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
180624180615 const pt = self.pt;
180625180616 const zcu = pt.zcu;
180617 const ip = &zcu.intern_pool;
180626180618 const bin_op = self.air.instructions.items(.data)[@backingInt(inst)].bin_op;
180627180619
180628180620 result: {
......@@ -180654,29 +180646,32 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
180654180646
180655180647 const elem_abi_size: u31 = @intCast(elem_ty.abiSize(zcu));
180656180648
180657 if (elem_abi_size == 1) {
180658 const dst_ptr: MCValue = switch (dst_ty.ptrSize(zcu)) {
180659 .slice => switch (dst) {
180660 .register_pair => |dst_regs| .{ .register = dst_regs[0] },
180661 else => dst,
180649 const dst_ptr: MCValue, const len: MCValue = switch (dst_ty.ptrSize(zcu)) {
180650 .slice => switch (dst) {
180651 else => .{ dst, dst.address().offset(8).deref() },
180652 .register_pair => |dst_regs| .{
180653 .{ .register = dst_regs[0] },
180654 .{ .register = dst_regs[1] },
180662180655 },
180663 .one => dst,
180664 .c, .many => unreachable,
180665 };
180666 const len: MCValue = switch (dst_ty.ptrSize(zcu)) {
180667 .slice => switch (dst) {
180668 .register_pair => |dst_regs| .{ .register = dst_regs[1] },
180669 else => dst.address().offset(8).deref(),
180656 .load_uav => |uav| switch (ip.indexToKey(uav.val)) {
180657 else => unreachable,
180658 .undef => .{ .undef, .undef },
180659 .slice => |slice| .{
180660 try self.lowerValue(.fromInterned(slice.ptr)),
180661 try self.lowerValue(.fromInterned(slice.len)),
180662 },
180670180663 },
180671 .one => .{ .immediate = dst_ty.childType(zcu).arrayLen(zcu) },
180672 .c, .many => unreachable,
180673 };
180674 const len_lock: ?RegisterLock = switch (len) {
180675 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
180676 else => null,
180677 };
180678 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
180664 },
180665 .one => .{ dst, .{ .immediate = dst_ty.childType(zcu).arrayLen(zcu) } },
180666 .c, .many => unreachable,
180667 };
180668 const len_lock: ?RegisterLock = switch (len) {
180669 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
180670 else => null,
180671 };
180672 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
180679180673
180674 if (elem_abi_size == 1) {
180680180675 try self.genInlineMemset(dst_ptr, src_val, len, .{ .safety = safety });
180681180676 break :result;
180682180677 }
......@@ -180684,26 +180679,18 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
180684180679 // Store the first element, and then rely on memcpy copying forwards.
180685180680 // Length zero requires a runtime check - so we handle arrays specially
180686180681 // here to elide it.
180687 switch (dst_ty.ptrSize(zcu)) {
180688 .slice => {
180682 switch (len) {
180683 else => {
180689180684 const slice_ptr_ty = dst_ty.slicePtrFieldType(zcu);
180690180685
180691 const dst_ptr: MCValue = switch (dst) {
180692 .register_pair => |dst_regs| .{ .register = dst_regs[0] },
180693 else => dst,
180694 };
180695 const len: MCValue = switch (dst) {
180696 .register_pair => |dst_regs| .{ .register = dst_regs[1] },
180697 else => dst.address().offset(8).deref(),
180698 };
180699
180700180686 // Used to store the number of elements for comparison.
180701180687 // After comparison, updated to store number of bytes needed to copy.
180702180688 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
180703180689 const len_mcv: MCValue = .{ .register = len_reg };
180704 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
180705 defer self.register_manager.unlockReg(len_lock);
180690 const len_reg_lock = self.register_manager.lockRegAssumeUnused(len_reg);
180691 defer self.register_manager.unlockReg(len_reg_lock);
180706180692
180693 try self.spillEflagsIfOccupied();
180707180694 try self.genSetReg(len_reg, .usize, len, .{});
180708180695 try self.asmRegisterRegister(.{ ._, .@"test" }, len_reg, len_reg);
180709180696
......@@ -180733,12 +180720,10 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
180733180720
180734180721 self.performReloc(skip_reloc);
180735180722 },
180736 .one => {
180723 .immediate => |len_imm| {
180737180724 const elem_ptr_ty = try pt.singleMutPtrType(elem_ty);
180738180725
180739 const len = dst_ty.childType(zcu).arrayLen(zcu);
180740
180741 assert(len != 0); // prevented by Sema
180726 assert(len_imm != 0); // prevented by Sema
180742180727 try self.store(elem_ptr_ty, dst, src_val, .{ .safety = safety });
180743180728
180744180729 const second_elem_ptr_reg =
......@@ -180753,10 +180738,9 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
180753180738 .off = elem_abi_size,
180754180739 } }, .{});
180755180740
180756 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) };
180741 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len_imm - 1) };
180757180742 try self.genInlineMemcpy(second_elem_ptr_mcv, dst, bytes_to_copy, .{ .no_alias = false });
180758180743 },
180759 .c, .many => unreachable,
180760180744 }
180761180745 }
180762180746 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -182779,17 +182763,27 @@ const Temp = struct {
182779182763 assert(limb_index == 0);
182780182764 new_temp_index.tracking(cg).* = .init(.{ .lea_nav = nav });
182781182765 },
182782 .load_uav => |uav| {
182783 const new_reg =
182784 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
182785 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
182786 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
182787 .base = .{ .uav = uav },
182788 .mod = .{ .rm = .{
182789 .size = .qword,
182790 .disp = @as(u31, limb_index) * 8,
182791 } },
182792 });
182766 .load_uav => |uav| switch (cg.pt.zcu.intern_pool.indexToKey(uav.val)) {
182767 else => {
182768 const new_reg = try cg.register_manager.allocReg(
182769 new_temp_index.toIndex(),
182770 abi.RegisterClass.gp,
182771 );
182772 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
182773 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
182774 .base = .{ .uav = uav },
182775 .mod = .{ .rm = .{
182776 .size = .qword,
182777 .disp = @as(u31, limb_index) * 8,
182778 } },
182779 });
182780 },
182781 .slice => |slice| new_temp_index.tracking(cg).* =
182782 .init(try cg.lowerValue(.fromInterned(switch (limb_index) {
182783 else => unreachable,
182784 0 => slice.ptr,
182785 1 => slice.len,
182786 }))),
182793182787 },
182794182788 .lea_uav => |uav| {
182795182789 assert(limb_index == 0);
......@@ -182878,15 +182872,11 @@ const Temp = struct {
182878182872 fn toLimb(temp: *Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) InnerError!void {
182879182873 switch (temp.unwrap(cg)) {
182880182874 .ref => {},
182881 .temp => |temp_index| {
182875 .temp => |temp_index| inplace: {
182882182876 const temp_tracking = temp_index.tracking(cg);
182883182877 switch (temp_tracking.short) {
182884 else => {},
182885 .register, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym => {
182886 assert(limb_index == 0);
182887 cg.temp_type[@backingInt(temp_index)] = limb_ty;
182888 return;
182889 },
182878 else => break :inplace,
182879 .register, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym => assert(limb_index == 0),
182890182880 .register_pair => |regs| {
182891182881 switch (temp_tracking.long) {
182892182882 .none, .reserved_frame => {},
......@@ -182896,8 +182886,6 @@ const Temp = struct {
182896182886 for (regs, 0..) |reg, reg_index| if (reg_index != limb_index)
182897182887 cg.register_manager.freeReg(reg);
182898182888 temp_tracking.* = .init(.{ .register = regs[limb_index] });
182899 cg.temp_type[@backingInt(temp_index)] = limb_ty;
182900 return;
182901182889 },
182902182890 .load_frame => |frame_addr| if (!frame_addr.index.isNamed()) {
182903182891 assert(std.meta.eql(temp_tracking.long.load_frame, frame_addr));
......@@ -182905,10 +182893,19 @@ const Temp = struct {
182905182893 .index = frame_addr.index,
182906182894 .off = frame_addr.off + @as(u31, limb_index) * 8,
182907182895 } });
182908 cg.temp_type[@backingInt(temp_index)] = limb_ty;
182909 return;
182896 },
182897 .load_uav => |uav| switch (cg.pt.zcu.intern_pool.indexToKey(uav.val)) {
182898 else => break :inplace,
182899 .slice => |slice| temp_tracking.* =
182900 .init(try cg.lowerValue(.fromInterned(switch (limb_index) {
182901 else => unreachable,
182902 0 => slice.ptr,
182903 1 => slice.len,
182904 }))),
182910182905 },
182911182906 }
182907 cg.temp_type[@backingInt(temp_index)] = limb_ty;
182908 return;
182912182909 },
182913182910 .err_ret_trace => unreachable,
182914182911 }
src/codegen/x86_64/Emit.zig-7
......@@ -536,14 +536,12 @@ pub fn emitMir(emit: *Emit) Error!void {
536536 .column = emit.prev_di_loc.column,
537537 .end = true,
538538 }),
539 .pseudo_dbg_arg_none,
540539 .pseudo_dbg_arg_i_s,
541540 .pseudo_dbg_arg_i_u,
542541 .pseudo_dbg_arg_i_64,
543542 .pseudo_dbg_arg_ro,
544543 .pseudo_dbg_arg_fa,
545544 .pseudo_dbg_arg_m,
546 .pseudo_dbg_var_none,
547545 .pseudo_dbg_var_i_s,
548546 .pseudo_dbg_var_i_u,
549547 .pseudo_dbg_var_i_64,
......@@ -560,7 +558,6 @@ pub fn emitMir(emit: *Emit) Error!void {
560558 var loc_buf: [2]DwarfLoc = undefined;
561559 const loc: DwarfLoc = loc: switch (mir_inst.ops) {
562560 else => unreachable,
563 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
564561 .pseudo_dbg_arg_i_s,
565562 .pseudo_dbg_arg_i_u,
566563 .pseudo_dbg_var_i_s,
......@@ -632,23 +629,19 @@ pub fn emitMir(emit: *Emit) Error!void {
632629 try dwarf.genLocalVarDebugInfo(
633630 switch (mir_inst.ops) {
634631 else => unreachable,
635 .pseudo_dbg_arg_none,
636632 .pseudo_dbg_arg_i_s,
637633 .pseudo_dbg_arg_i_u,
638634 .pseudo_dbg_arg_i_64,
639635 .pseudo_dbg_arg_ro,
640636 .pseudo_dbg_arg_fa,
641637 .pseudo_dbg_arg_m,
642 .pseudo_dbg_arg_val,
643638 => .arg,
644 .pseudo_dbg_var_none,
645639 .pseudo_dbg_var_i_s,
646640 .pseudo_dbg_var_i_u,
647641 .pseudo_dbg_var_i_64,
648642 .pseudo_dbg_var_ro,
649643 .pseudo_dbg_var_fa,
650644 .pseudo_dbg_var_m,
651 .pseudo_dbg_var_val,
652645 => .local_var,
653646 },
654647 local.name.toSlice(&emit.lower.mir),
src/codegen/x86_64/Lower.zig-2
......@@ -320,7 +320,6 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
320320 .pseudo_dbg_enter_inline_func,
321321 .pseudo_dbg_leave_inline_func,
322322 .pseudo_dbg_end_none,
323 .pseudo_dbg_arg_none,
324323 .pseudo_dbg_arg_i_s,
325324 .pseudo_dbg_arg_i_u,
326325 .pseudo_dbg_arg_i_64,
......@@ -329,7 +328,6 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
329328 .pseudo_dbg_arg_m,
330329 .pseudo_dbg_arg_val,
331330 .pseudo_dbg_var_args_none,
332 .pseudo_dbg_var_none,
333331 .pseudo_dbg_var_i_s,
334332 .pseudo_dbg_var_i_u,
335333 .pseudo_dbg_var_i_64,
src/codegen/x86_64/Mir.zig-6
......@@ -1547,9 +1547,6 @@ pub const Inst = struct {
15471547 /// Uses `none` payload.
15481548 pseudo_dbg_end_none,
15491549 /// Local argument.
1550 /// Uses `none` payload.
1551 pseudo_dbg_arg_none,
1552 /// Local argument.
15531550 /// Uses `i` payload.
15541551 pseudo_dbg_arg_i_s,
15551552 /// Local argument.
......@@ -1573,9 +1570,6 @@ pub const Inst = struct {
15731570 /// Remaining arguments are varargs.
15741571 pseudo_dbg_var_args_none,
15751572 /// Local variable.
1576 /// Uses `none` payload.
1577 pseudo_dbg_var_none,
1578 /// Local variable.
15791573 /// Uses `i` payload.
15801574 pseudo_dbg_var_i_s,
15811575 /// Local variable.
test/behavior/memcpy.zig+29
......@@ -180,3 +180,32 @@ test "@memcpy no sentinel source into sentinel destination" {
180180 S.doTheTest();
181181 comptime S.doTheTest();
182182}
183
184test "@memcpy a global array" {
185 const S = struct {
186 var array_u8: [1]u8 = .{1};
187 const slice_u8: []u8 = &array_u8;
188 var array_u32: [1]u32 = .{10};
189 const slice_u32: []u32 = &array_u32;
190 };
191
192 try expect(S.array_u8[0] == 1);
193 @memcpy(&S.array_u8, &[1]u8{2});
194 try expect(S.array_u8[0] == 2);
195 @memcpy(&S.array_u8, &[1]u8{S.array_u8[0] + 1});
196 try expect(S.array_u8[0] == 3);
197 @memcpy(S.slice_u8, &[1]u8{4});
198 try expect(S.array_u8[0] == 4);
199 @memcpy(S.slice_u8, &[1]u8{S.array_u8[0] + 1});
200 try expect(S.array_u8[0] == 5);
201
202 try expect(S.array_u32[0] == 10);
203 @memcpy(&S.array_u32, &[1]u32{20});
204 try expect(S.array_u32[0] == 20);
205 @memcpy(&S.array_u32, &[1]u32{S.array_u32[0] + 10});
206 try expect(S.array_u32[0] == 30);
207 @memcpy(S.slice_u32, &[1]u32{40});
208 try expect(S.array_u32[0] == 40);
209 @memcpy(S.slice_u32, &[1]u32{S.array_u32[0] + 10});
210 try expect(S.array_u32[0] == 50);
211}
test/behavior/memmove.zig+29
......@@ -170,3 +170,32 @@ comptime {
170170 s.set("hello");
171171 if (!std.mem.eql(u8, s.buffer[0..8], "hehelloo")) @compileError("bad");
172172}
173
174test "@memmove a global array" {
175 const S = struct {
176 var array_u8: [1]u8 = .{1};
177 const slice_u8: []u8 = &array_u8;
178 var array_u32: [1]u32 = .{10};
179 const slice_u32: []u32 = &array_u32;
180 };
181
182 try expect(S.array_u8[0] == 1);
183 @memmove(&S.array_u8, &[1]u8{2});
184 try expect(S.array_u8[0] == 2);
185 @memmove(&S.array_u8, &[1]u8{S.array_u8[0] + 1});
186 try expect(S.array_u8[0] == 3);
187 @memmove(S.slice_u8, &[1]u8{4});
188 try expect(S.array_u8[0] == 4);
189 @memmove(S.slice_u8, &[1]u8{S.array_u8[0] + 1});
190 try expect(S.array_u8[0] == 5);
191
192 try expect(S.array_u32[0] == 10);
193 @memmove(&S.array_u32, &[1]u32{20});
194 try expect(S.array_u32[0] == 20);
195 @memmove(&S.array_u32, &[1]u32{S.array_u32[0] + 10});
196 try expect(S.array_u32[0] == 30);
197 @memmove(S.slice_u32, &[1]u32{40});
198 try expect(S.array_u32[0] == 40);
199 @memmove(S.slice_u32, &[1]u32{S.array_u32[0] + 10});
200 try expect(S.array_u32[0] == 50);
201}
test/behavior/memset.zig+24-6
......@@ -204,13 +204,31 @@ test "@memset a global array" {
204204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
205205
206206 const S = struct {
207 var buf: [1]u32 = .{123};
207 var array_u8: [1]u8 = .{1};
208 const slice_u8: []u8 = &array_u8;
209 var array_u32: [1]u32 = .{10};
210 const slice_u32: []u32 = &array_u32;
208211 };
209 try expect(S.buf[0] == 123);
210 @memset(&S.buf, 456);
211 try expect(S.buf[0] == 456);
212 @memset(&S.buf, S.buf[0] + 333);
213 try expect(S.buf[0] == 789);
212
213 try expect(S.array_u8[0] == 1);
214 @memset(&S.array_u8, 2);
215 try expect(S.array_u8[0] == 2);
216 @memset(&S.array_u8, S.array_u8[0] + 1);
217 try expect(S.array_u8[0] == 3);
218 @memset(S.slice_u8, 4);
219 try expect(S.array_u8[0] == 4);
220 @memset(S.slice_u8, S.array_u8[0] + 1);
221 try expect(S.array_u8[0] == 5);
222
223 try expect(S.array_u32[0] == 10);
224 @memset(&S.array_u32, 20);
225 try expect(S.array_u32[0] == 20);
226 @memset(&S.array_u32, S.array_u32[0] + 10);
227 try expect(S.array_u32[0] == 30);
228 @memset(S.slice_u32, 40);
229 try expect(S.array_u32[0] == 40);
230 @memset(S.slice_u32, S.array_u32[0] + 10);
231 try expect(S.array_u32[0] == 50);
214232}
215233
216234test "@memset array of booleans" {