aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-04-23 22:15:45 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-04-25 11:23:41 -0700
commit58fabbc903eb5c75a02bedd8653f4c045c458f31 (patch)
tree3539b300aebd4abe9a2c85c91795a91e6ef523d7 /src
parent881e931ee1758dee469c3f87700413bb321c9f43 (diff)
downloadzig-58fabbc903eb5c75a02bedd8653f4c045c458f31.tar.gz
zig-58fabbc903eb5c75a02bedd8653f4c045c458f31.zip
x86_64 backend: support `@memset` with slices
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig56
1 files changed, 48 insertions, 8 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 7b63c28c9f..316322c60b 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -8175,7 +8175,15 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
};
defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
- if (elem_ty.abiSize(self.target.*) == 1) {
+ const elem_abi_size = @intCast(u31, elem_ty.abiSize(self.target.*));
+
+ if (elem_abi_size == 1) {
+ const ptr = switch (dst_ptr_ty.ptrSize()) {
+ // TODO: this only handles slices stored in the stack
+ .Slice => @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 0 }),
+ .One => dst_ptr,
+ .C, .Many => unreachable,
+ };
const len = switch (dst_ptr_ty.ptrSize()) {
// TODO: this only handles slices stored in the stack
.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 {
};
defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
- // TODO: dst_ptr could be a slice rather than raw pointer
- try self.genInlineMemset(dst_ptr, src_val, len, .{});
+ try self.genInlineMemset(ptr, src_val, len, .{});
return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -8198,12 +8205,47 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
// here to elide it.
switch (dst_ptr_ty.ptrSize()) {
.Slice => {
+ var buf: Type.SlicePtrFieldTypeBuffer = undefined;
+ const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf);
+
// TODO: this only handles slices stored in the stack
const ptr = @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 0 });
const len = @as(MCValue, .{ .stack_offset = dst_ptr.stack_offset - 8 });
- _ = ptr;
- _ = len;
- return self.fail("TODO implement airMemset for x86_64 with ABI size > 1 using a slice", .{});
+
+ // Used to store the number of elements for comparison.
+ // After comparison, updated to store number of bytes needed to copy.
+ const len_reg = try self.register_manager.allocReg(null, gp);
+ const len_mcv: MCValue = .{ .register = len_reg };
+ const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
+ defer self.register_manager.unlockReg(len_lock);
+
+ try self.asmRegisterMemory(.mov, len_reg, Memory.sib(.qword, .{
+ .base = .rbp,
+ .disp = -len.stack_offset,
+ }));
+
+ const skip_reloc = try self.asmJccReloc(undefined, .z);
+ try self.store(ptr, src_val, slice_ptr_ty, elem_ty);
+
+ const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);
+ const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
+ const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
+ defer self.register_manager.unlockReg(second_elem_ptr_lock);
+
+ try self.asmRegisterMemory(
+ .lea,
+ second_elem_ptr_reg,
+ Memory.sib(.qword, .{
+ .base = try self.copyToTmpRegister(Type.usize, ptr),
+ .disp = elem_abi_size,
+ }),
+ );
+
+ try self.genBinOpMir(.sub, Type.usize, len_mcv, .{ .immediate = 1 });
+ try self.asmRegisterRegisterImmediate(.imul, len_reg, len_reg, Immediate.u(elem_abi_size));
+ try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv, .{});
+
+ try self.performReloc(skip_reloc);
},
.One => {
const len = dst_ptr_ty.childType().arrayLen();
@@ -8215,8 +8257,6 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
defer self.register_manager.unlockReg(second_elem_ptr_lock);
- const elem_abi_size = @intCast(u31, elem_ty.abiSize(self.target.*));
-
try self.asmRegisterMemory(
.lea,
second_elem_ptr_reg,