| ... | ... | @@ -1318,37 +1318,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1318 | 1318 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1319 | 1319 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1320 | 1320 | |
| 1321 | | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1322 | | const index_mcv: MCValue = blk: { |
| 1323 | | switch (try self.resolveInst(bin_op.rhs)) { |
| 1324 | | .register => |reg| { |
| 1325 | | if (reg.to64() != .rcx) { |
| 1326 | | try self.register_manager.getReg(.rcx, inst); |
| 1327 | | } |
| 1328 | | break :blk MCValue{ .register = .rcx }; |
| 1329 | | }, |
| 1330 | | else => return self.fail("TODO move index mcv into a register", .{}), |
| 1331 | | } |
| 1321 | const offset_reg = blk: { |
| 1322 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1323 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1324 | const offset_reg = try self.register_manager.allocReg(null, &.{}); |
| 1325 | try self.genSetReg(index_ty, offset_reg, index_mcv); |
| 1326 | try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size }); |
| 1327 | break :blk offset_reg; |
| 1332 | 1328 | }; |
| 1333 | 1329 | |
| 1334 | | try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size }); |
| 1335 | | |
| 1336 | 1330 | const dst_mcv = blk: { |
| 1337 | 1331 | switch (slice_mcv) { |
| 1338 | | .stack_offset => |unadjusted_off| { |
| 1332 | .stack_offset => |off| { |
| 1339 | 1333 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1340 | | const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register}); |
| 1341 | | const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*)); |
| 1342 | | const off = unadjusted_off + elem_size; |
| 1343 | | // lea reg, [rbp - 8 + rcx*1] |
| 1334 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); |
| 1335 | // mov reg, [rbp - 8] |
| 1344 | 1336 | _ = try self.addInst(.{ |
| 1345 | | .tag = .lea, |
| 1337 | .tag = .mov, |
| 1346 | 1338 | .ops = (Mir.Ops{ |
| 1347 | | .reg1 = registerAlias(addr_reg, slice_ptr_abi_size), |
| 1339 | .reg1 = addr_reg.to64(), |
| 1348 | 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 | 1351 | }).encode(), |
| 1351 | | .data = .{ .imm = -@intCast(i32, off) }, |
| 1352 | .data = undefined, |
| 1352 | 1353 | }); |
| 1353 | 1354 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| 1354 | 1355 | break :blk dst_mcv; |
| ... | ... | @@ -1528,7 +1529,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1528 | 1529 | &.{ reg, .rax, .rcx }, |
| 1529 | 1530 | ); |
| 1530 | 1531 | const addr_reg = regs[0]; |
| 1531 | | const len_reg = regs[1]; |
| 1532 | const count_reg = regs[1]; |
| 1532 | 1533 | const tmp_reg = regs[2]; |
| 1533 | 1534 | |
| 1534 | 1535 | _ = try self.addInst(.{ |
| ... | ... | @@ -1544,12 +1545,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1544 | 1545 | try self.register_manager.getReg(.rcx, null); |
| 1545 | 1546 | |
| 1546 | 1547 | // 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) }); |
| 1548 | 1549 | |
| 1549 | 1550 | return self.genInlineMemcpy( |
| 1550 | 1551 | -@intCast(i32, off + abi_size), |
| 1551 | 1552 | registerAlias(addr_reg, @divExact(reg.size(), 8)), |
| 1552 | | len_reg.to64(), |
| 1553 | count_reg.to64(), |
| 1553 | 1554 | tmp_reg.to8(), |
| 1554 | 1555 | ); |
| 1555 | 1556 | }, |
| ... | ... | @@ -1592,11 +1593,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1592 | 1593 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1593 | 1594 | } |
| 1594 | 1595 | |
| 1595 | | fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1596 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 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); |
| 1596 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 1597 | _ = ptr_ty; |
| 1600 | 1598 | switch (ptr) { |
| 1601 | 1599 | .none => unreachable, |
| 1602 | 1600 | .undef => unreachable, |
| ... | ... | @@ -1605,19 +1603,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1605 | 1603 | .compare_flags_unsigned => unreachable, |
| 1606 | 1604 | .compare_flags_signed => unreachable, |
| 1607 | 1605 | .immediate => |imm| { |
| 1608 | | try self.setRegOrMem(elem_ty, .{ .memory = imm }, value); |
| 1606 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 1609 | 1607 | }, |
| 1610 | 1608 | .ptr_stack_offset => |off| { |
| 1611 | | try self.genSetStack(elem_ty, off, value); |
| 1609 | try self.genSetStack(value_ty, off, value); |
| 1612 | 1610 | }, |
| 1613 | 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 | 1614 | .embedded_in_code => { |
| 1617 | 1615 | return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); |
| 1618 | 1616 | }, |
| 1619 | 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 | 1659 | .memory => { |
| 1623 | 1660 | return self.fail("TODO implement storing to MCValue.memory", .{}); |
| ... | ... | @@ -1626,6 +1663,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1626 | 1663 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); |
| 1627 | 1664 | }, |
| 1628 | 1665 | } |
| 1666 | } |
| 1667 | |
| 1668 | fn 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 | 1675 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1630 | 1676 | } |
| 1631 | 1677 | |
| ... | ... | @@ -1653,9 +1699,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 1653 | 1699 | |
| 1654 | 1700 | switch (mcv) { |
| 1655 | 1701 | .ptr_stack_offset => |off| { |
| 1656 | | break :result MCValue{ |
| 1657 | | .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size, |
| 1658 | | }; |
| 1702 | const ptr_stack_offset = off - struct_size + struct_field_offset + struct_field_size; |
| 1703 | break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; |
| 1659 | 1704 | }, |
| 1660 | 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 | 1722 | |
| 1678 | 1723 | switch (mcv) { |
| 1679 | 1724 | .stack_offset => |off| { |
| 1680 | | break :result MCValue{ |
| 1681 | | .stack_offset = off + struct_size - struct_field_offset - struct_field_size, |
| 1682 | | }; |
| 1725 | const stack_offset = off - struct_size + struct_field_offset + struct_field_size; |
| 1726 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1683 | 1727 | }, |
| 1684 | 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 | 2000 | .immediate => |imm| { |
| 1957 | 2001 | // TODO take into account the type's ABI size when selecting the register alias |
| 1958 | 2002 | // register, immediate |
| 1959 | | if (imm <= math.maxInt(i32)) { |
| 2003 | if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) { |
| 1960 | 2004 | _ = try self.addInst(.{ |
| 1961 | 2005 | .tag = .imul_complex, |
| 1962 | 2006 | .ops = (Mir.Ops{ |
| ... | ... | @@ -3166,7 +3210,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3166 | 3210 | |
| 3167 | 3211 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); |
| 3168 | 3212 | const addr_reg = regs[0]; |
| 3169 | | const len_reg = regs[1]; |
| 3213 | const count_reg = regs[1]; |
| 3170 | 3214 | const tmp_reg = regs[2]; |
| 3171 | 3215 | |
| 3172 | 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 | 3226 | }); |
| 3183 | 3227 | |
| 3184 | 3228 | // 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) }); |
| 3186 | 3230 | |
| 3187 | 3231 | return self.genInlineMemcpy( |
| 3188 | 3232 | -@intCast(i32, stack_offset + abi_size), |
| 3189 | 3233 | addr_reg.to64(), |
| 3190 | | len_reg.to64(), |
| 3234 | count_reg.to64(), |
| 3191 | 3235 | tmp_reg.to8(), |
| 3192 | 3236 | ); |
| 3193 | 3237 | }, |
| ... | ... | @@ -3198,7 +3242,7 @@ fn genInlineMemcpy( |
| 3198 | 3242 | self: *Self, |
| 3199 | 3243 | stack_offset: i32, |
| 3200 | 3244 | addr_reg: Register, |
| 3201 | | len_reg: Register, |
| 3245 | count_reg: Register, |
| 3202 | 3246 | tmp_reg: Register, |
| 3203 | 3247 | ) InnerError!void { |
| 3204 | 3248 | // mov rcx, 0 |
| ... | ... | @@ -3220,20 +3264,19 @@ fn genInlineMemcpy( |
| 3220 | 3264 | }); |
| 3221 | 3265 | |
| 3222 | 3266 | // loop: |
| 3223 | | // cmp rcx, len |
| 3267 | // cmp count, 0 |
| 3224 | 3268 | const loop_start = try self.addInst(.{ |
| 3225 | 3269 | .tag = .cmp, |
| 3226 | 3270 | .ops = (Mir.Ops{ |
| 3227 | | .reg1 = .rcx, |
| 3228 | | .reg2 = len_reg, |
| 3271 | .reg1 = count_reg, |
| 3229 | 3272 | }).encode(), |
| 3230 | | .data = undefined, |
| 3273 | .data = .{ .imm = 0 }, |
| 3231 | 3274 | }); |
| 3232 | 3275 | |
| 3233 | | // jge end |
| 3276 | // je end |
| 3234 | 3277 | const loop_reloc = try self.addInst(.{ |
| 3235 | | .tag = .cond_jmp_above_below, |
| 3236 | | .ops = (Mir.Ops{ .flags = 0b00 }).encode(), |
| 3278 | .tag = .cond_jmp_eq_ne, |
| 3279 | .ops = (Mir.Ops{ .flags = 0b01 }).encode(), |
| 3237 | 3280 | .data = .{ .inst = undefined }, |
| 3238 | 3281 | }); |
| 3239 | 3282 | |
| ... | ... | @@ -3275,6 +3318,15 @@ fn genInlineMemcpy( |
| 3275 | 3318 | .data = .{ .imm = 1 }, |
| 3276 | 3319 | }); |
| 3277 | 3320 | |
| 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 | 3330 | // jmp loop |
| 3279 | 3331 | _ = try self.addInst(.{ |
| 3280 | 3332 | .tag = .jmp, |
| ... | ... | @@ -3286,47 +3338,6 @@ fn genInlineMemcpy( |
| 3286 | 3338 | try self.performReloc(loop_reloc); |
| 3287 | 3339 | } |
| 3288 | 3340 | |
| 3289 | | /// Set pointee via pointer stored in a register. |
| 3290 | | /// mov [reg], value |
| 3291 | | fn 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 | | |
| 3330 | 3341 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3331 | 3342 | switch (mcv) { |
| 3332 | 3343 | .dead => unreachable, |
| ... | ... | @@ -3749,7 +3760,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3749 | 3760 | if (typed_value.val.tag() == .int_u64) { |
| 3750 | 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 | 3766 | .Int => { |