authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-23 22:15:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-25 11:23:41-07:00
log58fabbc903eb5c75a02bedd8653f4c045c458f31
tree3539b300aebd4abe9a2c85c91795a91e6ef523d7
parent881e931ee1758dee469c3f87700413bb321c9f43

x86_64 backend: support `@memset` with slices


3 files changed, 50 insertions(+), 27 deletions(-)

lib/std/array_list.zig+2-14
......@@ -121,13 +121,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
121121
122122 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
123123 mem.copy(T, new_memory, self.items);
124
125 // TODO: write like this instead:
126 //@memset(self.items, undefined);
127 // first we need to implement memset with element ABI size > 1 in
128 // the x86_64 selfhosted backend.
129 @memset(@ptrCast([*]u8, self.items.ptr)[0..self.items.len * @sizeOf(T)], undefined);
130
124 @memset(self.items, undefined);
131125 self.clearAndFree();
132126 return new_memory;
133127 }
......@@ -603,13 +597,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
603597
604598 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
605599 mem.copy(T, new_memory, self.items);
606
607 // TODO: write like this instead:
608 //@memset(self.items, undefined);
609 // first we need to implement memset with element ABI size > 1 in
610 // the x86_64 selfhosted backend.
611 @memset(@ptrCast([*]u8, self.items.ptr)[0..self.items.len * @sizeOf(T)], undefined);
612
600 @memset(self.items, undefined);
613601 self.clearAndFree(allocator);
614602 return new_memory;
615603 }
src/arch/x86_64/CodeGen.zig+48-8
......@@ -8175,7 +8175,15 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
81758175 };
81768176 defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
81778177
8178 if (elem_ty.abiSize(self.target.*) == 1) {
8178 const elem_abi_size = @intCast(u31, elem_ty.abiSize(self.target.*));
8179
8180 if (elem_abi_size == 1) {
8181 const ptr = switch (dst_ptr_ty.ptrSize()) {
8182 // TODO: this only handles slices stored in the stack
8183 .Slice => @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 0 }),
8184 .One => dst_ptr,
8185 .C, .Many => unreachable,
8186 };
81798187 const len = switch (dst_ptr_ty.ptrSize()) {
81808188 // TODO: this only handles slices stored in the stack
81818189 .Slice => @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 8 }),
......@@ -8188,8 +8196,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
81888196 };
81898197 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
81908198
8191 // TODO: dst_ptr could be a slice rather than raw pointer
8192 try self.genInlineMemset(dst_ptr, src_val, len, .{});
8199 try self.genInlineMemset(ptr, src_val, len, .{});
81938200 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
81948201 }
81958202
......@@ -8198,12 +8205,47 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
81988205 // here to elide it.
81998206 switch (dst_ptr_ty.ptrSize()) {
82008207 .Slice => {
8208 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
8209 const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf);
8210
82018211 // TODO: this only handles slices stored in the stack
82028212 const ptr = @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 0 });
82038213 const len = @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 8 });
8204 _ = ptr;
8205 _ = len;
8206 return self.fail("TODO implement airMemset for x86_64 with ABI size > 1 using a slice", .{});
8214
8215 // Used to store the number of elements for comparison.
8216 // After comparison, updated to store number of bytes needed to copy.
8217 const len_reg = try self.register_manager.allocReg(null, gp);
8218 const len_mcv: MCValue = .{ .register = len_reg };
8219 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
8220 defer self.register_manager.unlockReg(len_lock);
8221
8222 try self.asmRegisterMemory(.mov, len_reg, Memory.sib(.qword, .{
8223 .base = .rbp,
8224 .disp = -len.stack_offset,
8225 }));
8226
8227 const skip_reloc = try self.asmJccReloc(undefined, .z);
8228 try self.store(ptr, src_val, slice_ptr_ty, elem_ty);
8229
8230 const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);
8231 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
8232 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
8233 defer self.register_manager.unlockReg(second_elem_ptr_lock);
8234
8235 try self.asmRegisterMemory(
8236 .lea,
8237 second_elem_ptr_reg,
8238 Memory.sib(.qword, .{
8239 .base = try self.copyToTmpRegister(Type.usize, ptr),
8240 .disp = elem_abi_size,
8241 }),
8242 );
8243
8244 try self.genBinOpMir(.sub, Type.usize, len_mcv, .{ .immediate = 1 });
8245 try self.asmRegisterRegisterImmediate(.imul, len_reg, len_reg, Immediate.u(elem_abi_size));
8246 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv, .{});
8247
8248 try self.performReloc(skip_reloc);
82078249 },
82088250 .One => {
82098251 const len = dst_ptr_ty.childType().arrayLen();
......@@ -8215,8 +8257,6 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
82158257 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
82168258 defer self.register_manager.unlockReg(second_elem_ptr_lock);
82178259
8218 const elem_abi_size = @intCast(u31, elem_ty.abiSize(self.target.*));
8219
82208260 try self.asmRegisterMemory(
82218261 .lea,
82228262 second_elem_ptr_reg,
test/behavior/basic.zig-5
......@@ -394,11 +394,6 @@ test "@memset on slices" {
394394 // TODO: implement memset on slices
395395 return error.SkipZigTest;
396396 }
397 if (builtin.zig_backend == .stage2_x86_64) {
398 // TODO: implement memset when element ABI size > 1
399 // TODO: implement memset on slices
400 return error.SkipZigTest;
401 }
402397
403398 try testMemsetSlice();
404399 try comptime testMemsetSlice();