diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-02-01 20:26:23 +0100 |
|---|---|---|
| committer | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-02-14 22:09:43 +0100 |
| commit | 77cf000438c8f65f089e9c64fbb881a9136f2931 (patch) | |
| tree | 3ee9587288b52cd62e5b9d945c0d3ccb6f8a0b46 /src/arch/aarch64/CodeGen.zig | |
| parent | 0d16e908fbb93cdaee80bc2514f76a09736bfa04 (diff) | |
| download | zig-77cf000438c8f65f089e9c64fbb881a9136f2931.tar.gz zig-77cf000438c8f65f089e9c64fbb881a9136f2931.zip | |
stage2 AArch64: implement loading from register
Diffstat (limited to 'src/arch/aarch64/CodeGen.zig')
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 138 |
1 files changed, 136 insertions, 2 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index fd9211d919..39eaa77ad5 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -1301,8 +1301,64 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo .embedded_in_code => { return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); }, - .register => { - return self.fail("TODO implement loading from MCValue.register for {}", .{self.target.cpu.arch}); + .register => |addr_reg| { + self.register_manager.freezeRegs(&.{addr_reg}); + defer self.register_manager.unfreezeRegs(&.{addr_reg}); + + switch (dst_mcv) { + .dead => unreachable, + .undef => unreachable, + .compare_flags_signed, .compare_flags_unsigned => unreachable, + .embedded_in_code => unreachable, + .stack_offset => |off| { + if (elem_ty.abiSize(self.target.*) <= 8) { + const tmp_reg = try self.register_manager.allocReg(null); + self.register_manager.freezeRegs(&.{tmp_reg}); + defer self.register_manager.unfreezeRegs(&.{tmp_reg}); + + try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); + try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); + } else { + // TODO optimize the register allocation + const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }); + self.register_manager.freezeRegs(®s); + defer self.register_manager.unfreezeRegs(®s); + + const src_reg = addr_reg; + const dst_reg = regs[0]; + const len_reg = regs[1]; + const count_reg = regs[2]; + const tmp_reg = regs[3]; + + // sub dst_reg, fp, #off + const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); + const adj_off = off + elem_size; + const offset = math.cast(u12, adj_off) catch return self.fail("TODO load: larger stack offsets", .{}); + _ = try self.addInst(.{ + .tag = .sub_immediate, + .data = .{ .rr_imm12_sh = .{ + .rd = dst_reg, + .rn = .x29, + .imm12 = offset, + } }, + }); + + // mov len, #elem_size + const len_imm = math.cast(u16, elem_size) catch return self.fail("TODO load: larger stack offsets", .{}); + _ = try self.addInst(.{ + .tag = .movk, + .data = .{ .r_imm16_sh = .{ + .rd = len_reg, + .imm16 = len_imm, + } }, + }); + + // memcpy(src, dst, len) + try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); + } + }, + else => return self.fail("TODO load from register into {}", .{dst_mcv}), + } }, .memory, .stack_offset, @@ -1317,6 +1373,84 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo } } +fn genInlineMemcpy( + self: *Self, + src: Register, + dst: Register, + len: Register, + count: Register, + tmp: Register, +) !void { + // movk count, #0 + _ = try self.addInst(.{ + .tag = .movk, + .data = .{ .r_imm16_sh = .{ + .rd = count, + .imm16 = 0, + } }, + }); + + // loop: + // cmp count, len + _ = try self.addInst(.{ + .tag = .cmp_shifted_register, + .data = .{ .rrr_imm6_shift = .{ + .rd = .xzr, + .rn = count, + .rm = len, + .imm6 = 0, + .shift = .lsl, + } }, + }); + + // bge end + _ = try self.addInst(.{ + .tag = .b_cond, + .data = .{ .inst_cond = .{ + .inst = @intCast(u32, self.mir_instructions.len + 5), + .cond = .ge, + } }, + }); + + // ldrb tmp, [src, count] + _ = try self.addInst(.{ + .tag = .ldrb_register, + .data = .{ .load_store_register_register = .{ + .rt = tmp, + .rn = src, + .offset = Instruction.LoadStoreOffset.reg(count).register, + } }, + }); + + // strb tmp, [dest, count] + _ = try self.addInst(.{ + .tag = .strb_register, + .data = .{ .load_store_register_register = .{ + .rt = tmp, + .rn = dst, + .offset = Instruction.LoadStoreOffset.reg(count).register, + } }, + }); + + // add count, count, #1 + _ = try self.addInst(.{ + .tag = .add_immediate, + .data = .{ .rr_imm12_sh = .{ + .rd = count, + .rn = count, + .imm12 = 1, + } }, + }); + + // b loop + _ = try self.addInst(.{ + .tag = .b, + .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 5) }, + }); + + // end: +} + fn airLoad(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const elem_ty = self.air.typeOfIndex(inst); |
