authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-03 19:32:52+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-04 01:21:24+01:00
logd288f202a4c0623531ac3f641c850a8401e719f8
tree8afcd9b9305d3d4e4cd4f02d727756d3502f9465
parente9f069f53627f1e647a200da7bb75e7663705c5f

stage2: implement slice_elem_val


3 files changed, 86 insertions(+), 18 deletions(-)

src/arch/x86_64/CodeGen.zig+67-17
......@@ -1274,7 +1274,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
12741274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12751275 const operand = try self.resolveInst(ty_op.operand);
12761276 const dst_mcv: MCValue = switch (operand) {
1277 .stack_offset => |off| MCValue{ .stack_offset = off + 4 },
1277 .stack_offset => |off| MCValue{ .stack_offset = off + 8 },
12781278 else => return self.fail("TODO implement slice_len for {}", .{operand}),
12791279 };
12801280 break :result dst_mcv;
......@@ -1303,10 +1303,57 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
13031303fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
13041304 const is_volatile = false; // TODO
13051305 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1306 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst))
1307 .dead
1308 else
1309 return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch});
1306 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
1307 const slice_mcv = try self.resolveInst(bin_op.lhs);
1308 const slice_ty = self.air.typeOf(bin_op.lhs);
1309
1310 const elem_ty = slice_ty.childType();
1311 const elem_size = elem_ty.abiSize(self.target.*);
1312
1313 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1314 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1315
1316 const index_ty = self.air.typeOf(bin_op.rhs);
1317 const index_mcv: MCValue = blk: {
1318 switch (try self.resolveInst(bin_op.rhs)) {
1319 .register => |reg| {
1320 if (reg.to64() != .rcx) {
1321 try self.register_manager.getReg(.rcx, inst);
1322 }
1323 break :blk MCValue{ .register = .rcx };
1324 },
1325 else => return self.fail("TODO move index mcv into a register", .{}),
1326 }
1327 };
1328
1329 try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size });
1330
1331 const dst_mcv = blk: {
1332 switch (slice_mcv) {
1333 .stack_offset => |unadjusted_off| {
1334 const dst_mcv = try self.allocRegOrMem(inst, false);
1335 const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register});
1336 const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*));
1337 const off = unadjusted_off + elem_size;
1338 // lea reg, [rbp - 8 + rcx*1]
1339 _ = try self.addInst(.{
1340 .tag = .lea,
1341 .ops = (Mir.Ops{
1342 .reg1 = registerAlias(addr_reg, slice_ptr_abi_size),
1343 .reg2 = .rbp,
1344 .flags = 0b11,
1345 }).encode(),
1346 .data = .{ .imm = -@intCast(i32, off) },
1347 });
1348 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1349 break :blk dst_mcv;
1350 },
1351 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
1352 }
1353 };
1354
1355 break :result dst_mcv;
1356 };
13101357 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13111358}
13121359
......@@ -1791,6 +1838,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
17911838 .data = .{ .imm = @intCast(i32, imm) },
17921839 });
17931840 } else {
1841 // TODO verify we don't spill and assign to the same register as dst_mcv
17941842 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
17951843 return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
17961844 }
......@@ -2906,12 +2954,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
29062954 },
29072955 }
29082956 },
2909 .embedded_in_code, .memory => {
2910 // TODO this and `.stack_offset` below need to get improved to support types greater than
2911 // register size, and do general memcpy
2912 const reg = try self.copyToTmpRegister(ty, mcv);
2913 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2914 },
29152957 .register => |reg| {
29162958 if (stack_offset > math.maxInt(i32)) {
29172959 return self.fail("stack offset too large", .{});
......@@ -2928,15 +2970,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
29282970 .data = .{ .imm = -@intCast(i32, adj_off) },
29292971 });
29302972 },
2931 .stack_offset => |off| {
2932 // TODO this and `.embedded_in_code` above need to get improved to support types greater than
2973 .stack_offset,
2974 .embedded_in_code,
2975 .memory,
2976 => {
2977 // TODO this needs to get improved to support types greater than
29332978 // register size, and do general memcpy
2979 if (mcv == .stack_offset and mcv.stack_offset == stack_offset) {
2980 // Copy stack variable to itself; nothing to do.
2981 return;
2982 }
29342983
2935 if (stack_offset == off)
2936 return; // Copy stack variable to itself; nothing to do.
2984 if (ty.abiSize(self.target.*) <= 8) {
2985 const reg = try self.copyToTmpRegister(ty, mcv);
2986 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2987 }
29372988
2938 const reg = try self.copyToTmpRegister(ty, mcv);
2939 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2989 return self.fail("TODO implement memcpy for ABI size {} > 8", .{ty.abiSize(self.target.*)});
29402990 },
29412991 }
29422992}
src/arch/x86_64/Isel.zig+18-1
......@@ -654,7 +654,24 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
654654 );
655655 }
656656 },
657 0b11 => return isel.fail("TODO unused variant lea reg1, reg2, 0b11", .{}),
657 0b11 => {
658 // lea reg, [rbp + rcx + imm32]
659 const imm = isel.mir.instructions.items(.data)[inst].imm;
660 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
661 return lowerToRmEnc(
662 .lea,
663 ops.reg1,
664 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
665 .disp = imm,
666 .base = src_reg,
667 .scale_index = .{
668 .scale = 0,
669 .index = .rcx,
670 },
671 }),
672 isel.code,
673 ) catch |err| isel.failWithLoweringError(err);
674 },
658675 }
659676}
660677
src/arch/x86_64/Mir.zig+1
......@@ -167,6 +167,7 @@ pub const Inst = struct {
167167 /// 0b00 reg1, [ds:imm32]
168168 /// 0b01 reg1, [rip + imm32]
169169 /// 0b10 reg1, [rip + reloc]
170 /// 0b11 reg1, [reg2 + rcx + imm32]
170171 /// Notes:
171172 /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate
172173 /// a valid relocation for.