From d288f202a4c0623531ac3f641c850a8401e719f8 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 Jan 2022 19:32:52 +0100 Subject: [PATCH] stage2: implement slice_elem_val --- src/arch/x86_64/CodeGen.zig | 84 +++++++++++++++++++++++++++++-------- src/arch/x86_64/Isel.zig | 19 ++++++++- src/arch/x86_64/Mir.zig | 1 + 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 6a01d019688d59b7e17c9ccf439d94b4cc42681b..99851b664f0e97ca7384590ab5c533ef0d953770 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1274,7 +1274,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(ty_op.operand); const dst_mcv: MCValue = switch (operand) { - .stack_offset => |off| MCValue{ .stack_offset = off + 4 }, + .stack_offset => |off| MCValue{ .stack_offset = off + 8 }, else => return self.fail("TODO implement slice_len for {}", .{operand}), }; break :result dst_mcv; @@ -1303,10 +1303,57 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = false; // TODO const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) - .dead - else - return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}); + const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { + const slice_mcv = try self.resolveInst(bin_op.lhs); + const slice_ty = self.air.typeOf(bin_op.lhs); + + const elem_ty = slice_ty.childType(); + const elem_size = elem_ty.abiSize(self.target.*); + + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); + + const index_ty = self.air.typeOf(bin_op.rhs); + const index_mcv: MCValue = blk: { + switch (try self.resolveInst(bin_op.rhs)) { + .register => |reg| { + if (reg.to64() != .rcx) { + try self.register_manager.getReg(.rcx, inst); + } + break :blk MCValue{ .register = .rcx }; + }, + else => return self.fail("TODO move index mcv into a register", .{}), + } + }; + + try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size }); + + const dst_mcv = blk: { + switch (slice_mcv) { + .stack_offset => |unadjusted_off| { + const dst_mcv = try self.allocRegOrMem(inst, false); + const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register}); + const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*)); + const off = unadjusted_off + elem_size; + // lea reg, [rbp - 8 + rcx*1] + _ = try self.addInst(.{ + .tag = .lea, + .ops = (Mir.Ops{ + .reg1 = registerAlias(addr_reg, slice_ptr_abi_size), + .reg2 = .rbp, + .flags = 0b11, + }).encode(), + .data = .{ .imm = -@intCast(i32, off) }, + }); + try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); + break :blk dst_mcv; + }, + else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), + } + }; + + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1791,6 +1838,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! .data = .{ .imm = @intCast(i32, imm) }, }); } else { + // TODO verify we don't spill and assign to the same register as dst_mcv const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv); return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); } @@ -2906,12 +2954,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro }, } }, - .embedded_in_code, .memory => { - // TODO this and `.stack_offset` below need to get improved to support types greater than - // register size, and do general memcpy - const reg = try self.copyToTmpRegister(ty, mcv); - return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); - }, .register => |reg| { if (stack_offset > math.maxInt(i32)) { return self.fail("stack offset too large", .{}); @@ -2928,15 +2970,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro .data = .{ .imm = -@intCast(i32, adj_off) }, }); }, - .stack_offset => |off| { - // TODO this and `.embedded_in_code` above need to get improved to support types greater than + .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) { + // Copy stack variable to itself; nothing to do. + return; + } - if (stack_offset == off) - return; // Copy stack variable to itself; nothing to do. + if (ty.abiSize(self.target.*) <= 8) { + const reg = try self.copyToTmpRegister(ty, mcv); + return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + } - 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.*)}); }, } } diff --git a/src/arch/x86_64/Isel.zig b/src/arch/x86_64/Isel.zig index 4bd064ae115a27f1a2cc62ca8987613c6ef35de4..e6d8278fdc1daf28e7f9689010343f778c0e2a8f 100644 --- a/src/arch/x86_64/Isel.zig +++ b/src/arch/x86_64/Isel.zig @@ -654,7 +654,24 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { ); } }, - 0b11 => return isel.fail("TODO unused variant lea reg1, reg2, 0b11", .{}), + 0b11 => { + // lea reg, [rbp + rcx + imm32] + const imm = isel.mir.instructions.items(.data)[inst].imm; + const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2; + return lowerToRmEnc( + .lea, + ops.reg1, + RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ + .disp = imm, + .base = src_reg, + .scale_index = .{ + .scale = 0, + .index = .rcx, + }, + }), + isel.code, + ) catch |err| isel.failWithLoweringError(err); + }, } } diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index d933181a6e2ea0ae9c526636c20d862f5e4f2d74..828addabfa314eeca0467f5f282a37444854d3f1 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -167,6 +167,7 @@ pub const Inst = struct { /// 0b00 reg1, [ds:imm32] /// 0b01 reg1, [rip + imm32] /// 0b10 reg1, [rip + reloc] + /// 0b11 reg1, [reg2 + rcx + imm32] /// Notes: /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate /// a valid relocation for. -- 2.54.0