aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86_64/CodeGen.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-01-18 11:58:22 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-01-18 11:58:22 +0100
commitaaa641feba8866ac38f2d06a8db2a24fa134e2f5 (patch)
tree3b528f866b44275ea4762d224bdfc6263c3fd273 /src/arch/x86_64/CodeGen.zig
parent4938fb8f5ca9551b69036fdb644103ffc9ef49cf (diff)
downloadzig-aaa641feba8866ac38f2d06a8db2a24fa134e2f5.tar.gz
zig-aaa641feba8866ac38f2d06a8db2a24fa134e2f5.zip
stage2: add inline memset for x86_64 backend
* introduce new Mir tag `mov_mem_index_imm` which selects instruction of the form `OP ptr [reg + rax*1 + imm32], imm32` where the encoded flags select the appropriate ptr width for memory store operation (note that scale is fixed and set at 1)
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
-rw-r--r--src/arch/x86_64/CodeGen.zig95
1 files changed, 93 insertions, 2 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 2cf585fe4e..213e460588 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -3148,7 +3148,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
- else => return self.fail("TODO implement memset", .{}),
+ else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }),
}
},
.compare_flags_unsigned => |op| {
@@ -3398,6 +3398,97 @@ fn genInlineMemcpy(
try self.performReloc(loop_reloc);
}
+fn genInlineMemset(self: *Self, ty: Type, stack_offset: u32, value: MCValue) InnerError!void {
+ try self.register_manager.getReg(.rax, null);
+ const abi_size = ty.abiSize(self.target.*);
+ const adj_off = stack_offset + abi_size;
+ if (adj_off > 128) {
+ return self.fail("TODO inline memset with large stack offset", .{});
+ }
+ const negative_offset = @bitCast(u32, -@intCast(i32, adj_off));
+
+ // We are actually counting `abi_size` bytes; however, we reuse the index register
+ // as both the counter and offset scaler, hence we need to subtract one from `abi_size`
+ // and count until -1.
+ if (abi_size > math.maxInt(i32)) {
+ // movabs rax, abi_size - 1
+ const payload = try self.addExtra(Mir.Imm64.encode(abi_size - 1));
+ _ = try self.addInst(.{
+ .tag = .movabs,
+ .ops = (Mir.Ops{
+ .reg1 = .rax,
+ }).encode(),
+ .data = .{ .payload = payload },
+ });
+ } else {
+ // mov rax, abi_size - 1
+ _ = try self.addInst(.{
+ .tag = .mov,
+ .ops = (Mir.Ops{
+ .reg1 = .rax,
+ }).encode(),
+ .data = .{ .imm = @truncate(u32, abi_size - 1) },
+ });
+ }
+
+ // loop:
+ // cmp rax, -1
+ const loop_start = try self.addInst(.{
+ .tag = .cmp,
+ .ops = (Mir.Ops{
+ .reg1 = .rax,
+ }).encode(),
+ .data = .{ .imm = @bitCast(u32, @as(i32, -1)) },
+ });
+
+ // je end
+ const loop_reloc = try self.addInst(.{
+ .tag = .cond_jmp_eq_ne,
+ .ops = (Mir.Ops{ .flags = 0b01 }).encode(),
+ .data = .{ .inst = undefined },
+ });
+
+ switch (value) {
+ .immediate => |x| {
+ if (x > math.maxInt(i32)) {
+ return self.fail("TODO inline memset for value immediate larger than 32bits", .{});
+ }
+ // mov byte ptr [rbp + rax + stack_offset], imm
+ const payload = try self.addExtra(Mir.ImmPair{
+ .dest_off = negative_offset,
+ .operand = @truncate(u32, x),
+ });
+ _ = try self.addInst(.{
+ .tag = .mov_mem_index_imm,
+ .ops = (Mir.Ops{
+ .reg1 = .rbp,
+ }).encode(),
+ .data = .{ .payload = payload },
+ });
+ },
+ else => return self.fail("TODO inline memset for value of type {}", .{value}),
+ }
+
+ // sub rax, 1
+ _ = try self.addInst(.{
+ .tag = .sub,
+ .ops = (Mir.Ops{
+ .reg1 = .rax,
+ }).encode(),
+ .data = .{ .imm = 1 },
+ });
+
+ // jmp loop
+ _ = try self.addInst(.{
+ .tag = .jmp,
+ .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
+ .data = .{ .inst = loop_start },
+ });
+
+ // end:
+ try self.performReloc(loop_reloc);
+}
+
fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
switch (mcv) {
.dead => unreachable,
@@ -3639,7 +3730,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
const stack_offset = try self.allocMem(inst, 16, 16);
const array_ty = ptr_ty.childType();
const array_len = array_ty.arrayLenIncludingSentinel();
- try self.genSetStack(Type.initTag(.usize), stack_offset + 8, ptr);
+ try self.genSetStack(ptr_ty, stack_offset + 8, ptr);
try self.genSetStack(Type.initTag(.u64), stack_offset + 16, .{ .immediate = array_len });
break :blk .{ .stack_offset = stack_offset };
};