Commit 384b19716d

Jakub Konka <kubkon@jakubkonka.com>
2022-01-03 20:51:49
stage2: implement inline memcpy
1 parent d288f20
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -2970,27 +2970,137 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
                 .data = .{ .imm = -@intCast(i32, adj_off) },
             });
         },
-        .stack_offset,
-        .embedded_in_code,
-        .memory,
-        => {
-            // TODO this needs to get improved to support types greater than
-            // register size, and do general memcpy
-            if (mcv == .stack_offset and mcv.stack_offset == stack_offset) {
+        .memory, .embedded_in_code => {
+            if (ty.abiSize(self.target.*) <= 8) {
+                const reg = try self.copyToTmpRegister(ty, mcv);
+                return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
+            }
+            return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
+        },
+        .stack_offset => |unadjusted_off| {
+            if (stack_offset == unadjusted_off) {
                 // Copy stack variable to itself; nothing to do.
                 return;
             }
 
-            if (ty.abiSize(self.target.*) <= 8) {
+            const abi_size = ty.abiSize(self.target.*);
+            if (abi_size <= 8) {
                 const reg = try self.copyToTmpRegister(ty, mcv);
                 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
             }
 
-            return self.fail("TODO implement memcpy for ABI size {} > 8", .{ty.abiSize(self.target.*)});
+            const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
+            const addr_reg = regs[0];
+            const len_reg = regs[1];
+
+            const off = unadjusted_off + abi_size;
+            _ = try self.addInst(.{
+                .tag = .lea,
+                .ops = (Mir.Ops{
+                    .reg1 = addr_reg.to64(),
+                    .reg2 = .rbp,
+                }).encode(),
+                .data = .{ .imm = -@intCast(i32, off) },
+            });
+
+            // TODO allow for abi_size to be u64
+            try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });
+
+            return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64());
         },
     }
 }
 
+fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: Register) InnerError!void {
+    try self.register_manager.getReg(.rax, null);
+    try self.register_manager.getReg(.rcx, null);
+    const tmp_reg = try self.register_manager.allocReg(null, &.{ addr_reg, len_reg, .rax, .rcx });
+
+    // mov rcx, 0
+    _ = try self.addInst(.{
+        .tag = .mov,
+        .ops = (Mir.Ops{
+            .reg1 = .rcx,
+        }).encode(),
+        .data = .{ .imm = 0 },
+    });
+
+    // mov rax, 0
+    _ = try self.addInst(.{
+        .tag = .mov,
+        .ops = (Mir.Ops{
+            .reg1 = .rax,
+        }).encode(),
+        .data = .{ .imm = 0 },
+    });
+
+    // loop:
+    // cmp rcx, len
+    const loop_start = try self.addInst(.{
+        .tag = .cmp,
+        .ops = (Mir.Ops{
+            .reg1 = .rcx,
+            .reg2 = len_reg,
+        }).encode(),
+        .data = undefined,
+    });
+
+    // jge end
+    const loop_reloc = try self.addInst(.{
+        .tag = .cond_jmp_above_below,
+        .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
+        .data = .{ .inst = undefined },
+    });
+
+    // mov tmp, [addr + rcx]
+    _ = try self.addInst(.{
+        .tag = .mov_scale_src,
+        .ops = (Mir.Ops{
+            .reg1 = tmp_reg.to8(),
+            .reg2 = addr_reg,
+        }).encode(),
+        .data = .{ .imm = 0 },
+    });
+
+    // mov [stack_offset + rax], tmp
+    _ = try self.addInst(.{
+        .tag = .mov_scale_dst,
+        .ops = (Mir.Ops{
+            .reg1 = .rbp,
+            .reg2 = tmp_reg.to8(),
+        }).encode(),
+        .data = .{ .imm = stack_offset },
+    });
+
+    // add rcx, 1
+    _ = try self.addInst(.{
+        .tag = .add,
+        .ops = (Mir.Ops{
+            .reg1 = .rcx,
+        }).encode(),
+        .data = .{ .imm = 1 },
+    });
+
+    // add rax, 1
+    _ = try self.addInst(.{
+        .tag = .add,
+        .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);
+}
+
 /// Set pointee via pointer stored in a register.
 /// mov [reg], value
 fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {