diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-04-23 22:15:45 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-04-25 11:23:41 -0700 |
| commit | 58fabbc903eb5c75a02bedd8653f4c045c458f31 (patch) | |
| tree | 3539b300aebd4abe9a2c85c91795a91e6ef523d7 /src | |
| parent | 881e931ee1758dee469c3f87700413bb321c9f43 (diff) | |
| download | zig-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.zig | 56 |
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, |
