authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-05 23:19:58+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-06 09:54:33+01:00
logb215241ef2153bf4b20f176923824e0e50d6da4c
treec4a68eb39e9086c687486205a2efdeda0dfe0789
parentf4aa276a0c665633980ea49bccb29da9d02d2ae1

stage2: fix airSliceElemVal

Refactor codegen and fix a bug in Isel.

4 files changed, 180 insertions(+), 130 deletions(-)

src/arch/x86_64/CodeGen.zig+105-94
...@@ -1318,37 +1318,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1318,37 +1318,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1318 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1318 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1319 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);1319 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
13201320
1321 const index_ty = self.air.typeOf(bin_op.rhs);1321 const offset_reg = blk: {
1322 const index_mcv: MCValue = blk: {1322 const index_ty = self.air.typeOf(bin_op.rhs);
1323 switch (try self.resolveInst(bin_op.rhs)) {1323 const index_mcv = try self.resolveInst(bin_op.rhs);
1324 .register => |reg| {1324 const offset_reg = try self.register_manager.allocReg(null, &.{});
1325 if (reg.to64() != .rcx) {1325 try self.genSetReg(index_ty, offset_reg, index_mcv);
1326 try self.register_manager.getReg(.rcx, inst);1326 try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size });
1327 }1327 break :blk offset_reg;
1328 break :blk MCValue{ .register = .rcx };
1329 },
1330 else => return self.fail("TODO move index mcv into a register", .{}),
1331 }
1332 };1328 };
13331329
1334 try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size });
1335
1336 const dst_mcv = blk: {1330 const dst_mcv = blk: {
1337 switch (slice_mcv) {1331 switch (slice_mcv) {
1338 .stack_offset => |unadjusted_off| {1332 .stack_offset => |off| {
1339 const dst_mcv = try self.allocRegOrMem(inst, false);1333 const dst_mcv = try self.allocRegOrMem(inst, false);
1340 const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register});1334 const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg});
1341 const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*));1335 // mov reg, [rbp - 8]
1342 const off = unadjusted_off + elem_size;
1343 // lea reg, [rbp - 8 + rcx*1]
1344 _ = try self.addInst(.{1336 _ = try self.addInst(.{
1345 .tag = .lea,1337 .tag = .mov,
1346 .ops = (Mir.Ops{1338 .ops = (Mir.Ops{
1347 .reg1 = registerAlias(addr_reg, slice_ptr_abi_size),1339 .reg1 = addr_reg.to64(),
1348 .reg2 = .rbp,1340 .reg2 = .rbp,
1349 .flags = 0b11,1341 .flags = 0b01,
1342 }).encode(),
1343 .data = .{ .imm = -@intCast(i32, off + 16) },
1344 });
1345 // add addr, offset
1346 _ = try self.addInst(.{
1347 .tag = .add,
1348 .ops = (Mir.Ops{
1349 .reg1 = addr_reg.to64(),
1350 .reg2 = offset_reg.to64(),
1350 }).encode(),1351 }).encode(),
1351 .data = .{ .imm = -@intCast(i32, off) },1352 .data = undefined,
1352 });1353 });
1353 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);1354 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1354 break :blk dst_mcv;1355 break :blk dst_mcv;
...@@ -1528,7 +1529,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1528,7 +1529,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1528 &.{ reg, .rax, .rcx },1529 &.{ reg, .rax, .rcx },
1529 );1530 );
1530 const addr_reg = regs[0];1531 const addr_reg = regs[0];
1531 const len_reg = regs[1];1532 const count_reg = regs[1];
1532 const tmp_reg = regs[2];1533 const tmp_reg = regs[2];
15331534
1534 _ = try self.addInst(.{1535 _ = try self.addInst(.{
...@@ -1544,12 +1545,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1544,12 +1545,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1544 try self.register_manager.getReg(.rcx, null);1545 try self.register_manager.getReg(.rcx, null);
15451546
1546 // TODO allow for abi size to be u641547 // TODO allow for abi size to be u64
1547 try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });1548 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
15481549
1549 return self.genInlineMemcpy(1550 return self.genInlineMemcpy(
1550 -@intCast(i32, off + abi_size),1551 -@intCast(i32, off + abi_size),
1551 registerAlias(addr_reg, @divExact(reg.size(), 8)),1552 registerAlias(addr_reg, @divExact(reg.size(), 8)),
1552 len_reg.to64(),1553 count_reg.to64(),
1553 tmp_reg.to8(),1554 tmp_reg.to8(),
1554 );1555 );
1555 },1556 },
...@@ -1592,11 +1593,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1592,11 +1593,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1592 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1593 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1593}1594}
15941595
1595fn airStore(self: *Self, inst: Air.Inst.Index) !void {1596fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
1596 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1597 _ = ptr_ty;
1597 const ptr = try self.resolveInst(bin_op.lhs);
1598 const value = try self.resolveInst(bin_op.rhs);
1599 const elem_ty = self.air.typeOf(bin_op.rhs);
1600 switch (ptr) {1598 switch (ptr) {
1601 .none => unreachable,1599 .none => unreachable,
1602 .undef => unreachable,1600 .undef => unreachable,
...@@ -1605,19 +1603,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1605,19 +1603,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1605 .compare_flags_unsigned => unreachable,1603 .compare_flags_unsigned => unreachable,
1606 .compare_flags_signed => unreachable,1604 .compare_flags_signed => unreachable,
1607 .immediate => |imm| {1605 .immediate => |imm| {
1608 try self.setRegOrMem(elem_ty, .{ .memory = imm }, value);1606 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
1609 },1607 },
1610 .ptr_stack_offset => |off| {1608 .ptr_stack_offset => |off| {
1611 try self.genSetStack(elem_ty, off, value);1609 try self.genSetStack(value_ty, off, value);
1612 },1610 },
1613 .ptr_embedded_in_code => |off| {1611 .ptr_embedded_in_code => |off| {
1614 try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value);1612 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
1615 },1613 },
1616 .embedded_in_code => {1614 .embedded_in_code => {
1617 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});1615 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
1618 },1616 },
1619 .register => |reg| {1617 .register => |reg| {
1620 try self.genSetPtrReg(elem_ty, reg, value);1618 switch (value) {
1619 .none => unreachable,
1620 .undef => unreachable,
1621 .dead => unreachable,
1622 .unreach => unreachable,
1623 .compare_flags_unsigned => unreachable,
1624 .compare_flags_signed => unreachable,
1625 .immediate => |imm| {
1626 const abi_size = value_ty.abiSize(self.target.*);
1627 switch (abi_size) {
1628 1, 2, 4 => {
1629 // TODO this is wasteful!
1630 // introduce new MIR tag specifically for mov [reg + 0], imm
1631 const payload = try self.addExtra(Mir.ImmPair{
1632 .dest_off = 0,
1633 .operand = @bitCast(i32, @intCast(u32, imm)),
1634 });
1635 _ = try self.addInst(.{
1636 .tag = .mov_mem_imm,
1637 .ops = (Mir.Ops{
1638 .reg1 = reg.to64(),
1639 .flags = switch (abi_size) {
1640 1 => 0b00,
1641 2 => 0b01,
1642 4 => 0b10,
1643 else => unreachable,
1644 },
1645 }).encode(),
1646 .data = .{ .payload = payload },
1647 });
1648 },
1649 else => {
1650 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
1651 },
1652 }
1653 },
1654 else => |other| {
1655 return self.fail("TODO implement set pointee with {}", .{other});
1656 },
1657 }
1621 },1658 },
1622 .memory => {1659 .memory => {
1623 return self.fail("TODO implement storing to MCValue.memory", .{});1660 return self.fail("TODO implement storing to MCValue.memory", .{});
...@@ -1626,6 +1663,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1626,6 +1663,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1626 return self.fail("TODO implement storing to MCValue.stack_offset", .{});1663 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
1627 },1664 },
1628 }1665 }
1666}
1667
1668fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1669 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1670 const ptr = try self.resolveInst(bin_op.lhs);
1671 const ptr_ty = self.air.typeOf(bin_op.lhs);
1672 const value = try self.resolveInst(bin_op.rhs);
1673 const value_ty = self.air.typeOf(bin_op.rhs);
1674 try self.store(ptr, value, ptr_ty, value_ty);
1629 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1675 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1630}1676}
16311677
...@@ -1653,9 +1699,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -1653,9 +1699,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
16531699
1654 switch (mcv) {1700 switch (mcv) {
1655 .ptr_stack_offset => |off| {1701 .ptr_stack_offset => |off| {
1656 break :result MCValue{1702 const ptr_stack_offset = off - struct_size + struct_field_offset + struct_field_size;
1657 .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size,1703 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
1658 };
1659 },1704 },
1660 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),1705 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
1661 }1706 }
...@@ -1677,9 +1722,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1677,9 +1722,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
16771722
1678 switch (mcv) {1723 switch (mcv) {
1679 .stack_offset => |off| {1724 .stack_offset => |off| {
1680 break :result MCValue{1725 const stack_offset = off - struct_size + struct_field_offset + struct_field_size;
1681 .stack_offset = off + struct_size - struct_field_offset - struct_field_size,1726 break :result MCValue{ .stack_offset = stack_offset };
1682 };
1683 },1727 },
1684 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),1728 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
1685 }1729 }
...@@ -1956,7 +2000,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !...@@ -1956,7 +2000,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
1956 .immediate => |imm| {2000 .immediate => |imm| {
1957 // TODO take into account the type's ABI size when selecting the register alias2001 // TODO take into account the type's ABI size when selecting the register alias
1958 // register, immediate2002 // register, immediate
1959 if (imm <= math.maxInt(i32)) {2003 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
1960 _ = try self.addInst(.{2004 _ = try self.addInst(.{
1961 .tag = .imul_complex,2005 .tag = .imul_complex,
1962 .ops = (Mir.Ops{2006 .ops = (Mir.Ops{
...@@ -3166,7 +3210,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3166,7 +3210,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31663210
3167 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });3211 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });
3168 const addr_reg = regs[0];3212 const addr_reg = regs[0];
3169 const len_reg = regs[1];3213 const count_reg = regs[1];
3170 const tmp_reg = regs[2];3214 const tmp_reg = regs[2];
31713215
3172 try self.register_manager.getReg(.rax, null);3216 try self.register_manager.getReg(.rax, null);
...@@ -3182,12 +3226,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3182,12 +3226,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3182 });3226 });
31833227
3184 // TODO allow for abi_size to be u643228 // TODO allow for abi_size to be u64
3185 try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) });3229 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
31863230
3187 return self.genInlineMemcpy(3231 return self.genInlineMemcpy(
3188 -@intCast(i32, stack_offset + abi_size),3232 -@intCast(i32, stack_offset + abi_size),
3189 addr_reg.to64(),3233 addr_reg.to64(),
3190 len_reg.to64(),3234 count_reg.to64(),
3191 tmp_reg.to8(),3235 tmp_reg.to8(),
3192 );3236 );
3193 },3237 },
...@@ -3198,7 +3242,7 @@ fn genInlineMemcpy(...@@ -3198,7 +3242,7 @@ fn genInlineMemcpy(
3198 self: *Self,3242 self: *Self,
3199 stack_offset: i32,3243 stack_offset: i32,
3200 addr_reg: Register,3244 addr_reg: Register,
3201 len_reg: Register,3245 count_reg: Register,
3202 tmp_reg: Register,3246 tmp_reg: Register,
3203) InnerError!void {3247) InnerError!void {
3204 // mov rcx, 03248 // mov rcx, 0
...@@ -3220,20 +3264,19 @@ fn genInlineMemcpy(...@@ -3220,20 +3264,19 @@ fn genInlineMemcpy(
3220 });3264 });
32213265
3222 // loop:3266 // loop:
3223 // cmp rcx, len3267 // cmp count, 0
3224 const loop_start = try self.addInst(.{3268 const loop_start = try self.addInst(.{
3225 .tag = .cmp,3269 .tag = .cmp,
3226 .ops = (Mir.Ops{3270 .ops = (Mir.Ops{
3227 .reg1 = .rcx,3271 .reg1 = count_reg,
3228 .reg2 = len_reg,
3229 }).encode(),3272 }).encode(),
3230 .data = undefined,3273 .data = .{ .imm = 0 },
3231 });3274 });
32323275
3233 // jge end3276 // je end
3234 const loop_reloc = try self.addInst(.{3277 const loop_reloc = try self.addInst(.{
3235 .tag = .cond_jmp_above_below,3278 .tag = .cond_jmp_eq_ne,
3236 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),3279 .ops = (Mir.Ops{ .flags = 0b01 }).encode(),
3237 .data = .{ .inst = undefined },3280 .data = .{ .inst = undefined },
3238 });3281 });
32393282
...@@ -3275,6 +3318,15 @@ fn genInlineMemcpy(...@@ -3275,6 +3318,15 @@ fn genInlineMemcpy(
3275 .data = .{ .imm = 1 },3318 .data = .{ .imm = 1 },
3276 });3319 });
32773320
3321 // sub count, 1
3322 _ = try self.addInst(.{
3323 .tag = .sub,
3324 .ops = (Mir.Ops{
3325 .reg1 = count_reg,
3326 }).encode(),
3327 .data = .{ .imm = 1 },
3328 });
3329
3278 // jmp loop3330 // jmp loop
3279 _ = try self.addInst(.{3331 _ = try self.addInst(.{
3280 .tag = .jmp,3332 .tag = .jmp,
...@@ -3286,47 +3338,6 @@ fn genInlineMemcpy(...@@ -3286,47 +3338,6 @@ fn genInlineMemcpy(
3286 try self.performReloc(loop_reloc);3338 try self.performReloc(loop_reloc);
3287}3339}
32883340
3289/// Set pointee via pointer stored in a register.
3290/// mov [reg], value
3291fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
3292 switch (mcv) {
3293 .dead => unreachable,
3294 .unreach, .none => return, // Nothing to do.
3295 .immediate => |imm| {
3296 const abi_size = ty.abiSize(self.target.*);
3297 switch (abi_size) {
3298 1, 2, 4 => {
3299 // TODO this is wasteful!
3300 // introduce new MIR tag specifically for mov [reg + 0], imm
3301 const payload = try self.addExtra(Mir.ImmPair{
3302 .dest_off = 0,
3303 .operand = @bitCast(i32, @intCast(u32, imm)),
3304 });
3305 _ = try self.addInst(.{
3306 .tag = .mov_mem_imm,
3307 .ops = (Mir.Ops{
3308 .reg1 = reg.to64(),
3309 .flags = switch (abi_size) {
3310 1 => 0b00,
3311 2 => 0b01,
3312 4 => 0b10,
3313 else => unreachable,
3314 },
3315 }).encode(),
3316 .data = .{ .payload = payload },
3317 });
3318 },
3319 else => {
3320 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
3321 },
3322 }
3323 },
3324 else => |other| {
3325 return self.fail("TODO implement set pointee with {}", .{other});
3326 },
3327 }
3328}
3329
3330fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {3341fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
3331 switch (mcv) {3342 switch (mcv) {
3332 .dead => unreachable,3343 .dead => unreachable,
...@@ -3749,7 +3760,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3749,7 +3760,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3749 if (typed_value.val.tag() == .int_u64) {3760 if (typed_value.val.tag() == .int_u64) {
3750 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };3761 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
3751 }3762 }
3752 return self.fail("TODO codegen more kinds of const pointers", .{});3763 return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()});
3753 },3764 },
3754 },3765 },
3755 .Int => {3766 .Int => {
src/arch/x86_64/Isel.zig+51-30
...@@ -265,32 +265,43 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I...@@ -265,32 +265,43 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I
265265
266fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {266fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
267 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);267 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
268 const flag = @truncate(u1, ops.flags);268 switch (ops.flags) {
269 if (flag == 0) {269 0b00 => {
270 const target = isel.mir.instructions.items(.data)[inst].inst;270 const target = isel.mir.instructions.items(.data)[inst].inst;
271 const source = isel.code.items.len;271 const source = isel.code.items.len;
272 lowerToDEnc(tag, 0, isel.code) catch |err|272 lowerToDEnc(tag, 0, isel.code) catch |err|
273 return isel.failWithLoweringError(err);273 return isel.failWithLoweringError(err);
274 try isel.relocs.append(isel.bin_file.allocator, .{274 try isel.relocs.append(isel.bin_file.allocator, .{
275 .source = source,275 .source = source,
276 .target = target,276 .target = target,
277 .offset = isel.code.items.len - 4,277 .offset = isel.code.items.len - 4,
278 .length = 5,278 .length = 5,
279 });279 });
280 return;280 },
281 }281 0b01 => {
282 if (ops.reg1 == .none) {282 if (ops.reg1 == .none) {
283 // JMP/CALL [imm]283 // JMP/CALL [imm]
284 const imm = isel.mir.instructions.items(.data)[inst].imm;284 const imm = isel.mir.instructions.items(.data)[inst].imm;
285 const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {285 const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {
286 16 => .word_ptr,286 16 => .word_ptr,
287 else => .qword_ptr,287 else => .qword_ptr,
288 };288 };
289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|
290 isel.failWithLoweringError(err);290 isel.failWithLoweringError(err);
291 }
292 // JMP/CALL reg
293 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err);
294 },
295 0b10 => {
296 // JMP/CALL r/m64
297 const imm = isel.mir.instructions.items(.data)[inst].imm;
298 return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
299 .disp = imm,
300 .base = ops.reg1,
301 }), isel.code) catch |err| isel.failWithLoweringError(err);
302 },
303 0b11 => return isel.fail("TODO unused JMP/CALL variant 0b11", .{}),
291 }304 }
292 // JMP/CALL reg
293 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err);
294}305}
295306
296fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {307fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
...@@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
658 // lea reg, [rbp + rcx + imm32]669 // lea reg, [rbp + rcx + imm32]
659 const imm = isel.mir.instructions.items(.data)[inst].imm;670 const imm = isel.mir.instructions.items(.data)[inst].imm;
660 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;671 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
672 const scale_index = ScaleIndex{
673 .scale = 0,
674 .index = .rcx,
675 };
661 return lowerToRmEnc(676 return lowerToRmEnc(
662 .lea,677 .lea,
663 ops.reg1,678 ops.reg1,
664 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{679 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
665 .disp = imm,680 .disp = imm,
666 .base = src_reg,681 .base = src_reg,
667 .scale_index = .{682 .scale_index = scale_index,
668 .scale = 0,
669 .index = .rcx,
670 },
671 }),683 }),
672 isel.code,684 isel.code,
673 ) catch |err| isel.failWithLoweringError(err);685 ) catch |err| isel.failWithLoweringError(err);
...@@ -1248,7 +1260,7 @@ const Memory = struct {...@@ -1248,7 +1260,7 @@ const Memory = struct {
1248 const dst = base.lowId();1260 const dst = base.lowId();
1249 const src = operand;1261 const src = operand;
1250 if (dst == 4 or mem_op.scale_index != null) {1262 if (dst == 4 or mem_op.scale_index != null) {
1251 if (mem_op.disp == 0) {1263 if (mem_op.disp == 0 and dst != 5) {
1252 encoder.modRm_SIBDisp0(src);1264 encoder.modRm_SIBDisp0(src);
1253 if (mem_op.scale_index) |si| {1265 if (mem_op.scale_index) |si| {
1254 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);1266 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);
...@@ -1916,6 +1928,15 @@ test "lower RM encoding" {...@@ -1916,6 +1928,15 @@ test "lower RM encoding" {
1916 },1928 },
1917 }), isel.code());1929 }), isel.code());
1918 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", isel.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");1930 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", isel.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
1931 try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{
1932 .disp = 0,
1933 .base = .rbp,
1934 .scale_index = .{
1935 .scale = 0,
1936 .index = .rcx,
1937 },
1938 }), isel.code());
1939 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", isel.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");
1919}1940}
19201941
1921test "lower MR encoding" {1942test "lower MR encoding" {
src/arch/x86_64/Mir.zig+5-6
...@@ -199,12 +199,11 @@ pub const Inst = struct {...@@ -199,12 +199,11 @@ pub const Inst = struct {
199 /// TODO handle scaling199 /// TODO handle scaling
200 movabs,200 movabs,
201201
202 /// ops flags: 0bX0:202 /// ops flags: form:
203 /// - Uses the `inst` Data tag as the jump target.203 /// 0b00 inst
204 /// - reg1 and reg2 are ignored.204 /// 0b01 reg1
205 /// ops flags: 0bX1:205 /// 0b01 [imm32] if reg1 is none
206 /// - reg1 is the jump target, reg2 and data are ignored.206 /// 0b10 [reg1 + imm32]
207 /// - if reg1 is none, [imm]
208 jmp,207 jmp,
209 call,208 call,
210209
test/stage2/x86_64.zig+19
...@@ -1761,6 +1761,25 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1761,6 +1761,25 @@ pub fn addCases(ctx: *TestContext) !void {
1761 \\}1761 \\}
1762 , "");1762 , "");
1763 }1763 }
1764
1765 {
1766 var case = ctx.exe("access slice element by index - slice_elem_val", target);
1767 case.addCompareOutput(
1768 \\var array = [_]usize{ 0, 42, 123, 34 };
1769 \\var slice: []const usize = &array;
1770 \\
1771 \\pub fn main() void {
1772 \\ assert(slice[0] == 0);
1773 \\ assert(slice[1] == 42);
1774 \\ assert(slice[2] == 123);
1775 \\ assert(slice[3] == 34);
1776 \\}
1777 \\
1778 \\fn assert(ok: bool) void {
1779 \\ if (!ok) unreachable;
1780 \\}
1781 , "");
1782 }
1764 }1783 }
1765}1784}
17661785