| ... | @@ -917,17 +917,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -917,17 +917,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 917 | const air_tags = self.air.instructions.items(.tag); | 917 | const air_tags = self.air.instructions.items(.tag); |
| 918 | | 918 | |
| 919 | for (body) |inst| { | 919 | for (body) |inst| { |
| 920 | // TODO: remove now-redundant isUnused calls from AIR handler functions | | |
| 921 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | | |
| 922 | continue; | | |
| 923 | } | | |
| 924 | | | |
| 925 | const old_air_bookkeeping = self.air_bookkeeping; | | |
| 926 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); | | |
| 927 | if (builtin.mode == .Debug) { | 920 | if (builtin.mode == .Debug) { |
| 928 | const mir_inst = @intCast(Mir.Inst.Index, self.mir_instructions.len); | 921 | const mir_inst = @intCast(Mir.Inst.Index, self.mir_instructions.len); |
| 929 | try self.mir_to_air_map.put(self.gpa, mir_inst, inst); | 922 | try self.mir_to_air_map.put(self.gpa, mir_inst, inst); |
| 930 | } | 923 | } |
| | 924 | |
| | 925 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; |
| 931 | if (debug_wip_mir) @import("../../print_air.zig").dumpInst( | 926 | if (debug_wip_mir) @import("../../print_air.zig").dumpInst( |
| 932 | inst, | 927 | inst, |
| 933 | self.bin_file.options.module.?, | 928 | self.bin_file.options.module.?, |
| ... | @@ -935,6 +930,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -935,6 +930,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 935 | self.liveness, | 930 | self.liveness, |
| 936 | ); | 931 | ); |
| 937 | | 932 | |
| | 933 | const old_air_bookkeeping = self.air_bookkeeping; |
| | 934 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 938 | switch (air_tags[inst]) { | 935 | switch (air_tags[inst]) { |
| 939 | // zig fmt: off | 936 | // zig fmt: off |
| 940 | .not, | 937 | .not, |
| ... | @@ -1505,22 +1502,14 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty | ... | @@ -1505,22 +1502,14 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty |
| 1505 | } | 1502 | } |
| 1506 | | 1503 | |
| 1507 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | 1504 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1508 | const result: MCValue = result: { | 1505 | const stack_offset = try self.allocMemPtr(inst); |
| 1509 | if (self.liveness.isUnused(inst)) break :result .unreach; | 1506 | const result = MCValue{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1510 | | | |
| 1511 | const stack_offset = try self.allocMemPtr(inst); | | |
| 1512 | break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) }; | | |
| 1513 | }; | | |
| 1514 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 1507 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 1515 | } | 1508 | } |
| 1516 | | 1509 | |
| 1517 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | 1510 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1518 | const result: MCValue = result: { | 1511 | const stack_offset = try self.allocMemPtr(inst); |
| 1519 | if (self.liveness.isUnused(inst)) break :result .unreach; | 1512 | const result = MCValue{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1520 | | | |
| 1521 | const stack_offset = try self.allocMemPtr(inst); | | |
| 1522 | break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) }; | | |
| 1523 | }; | | |
| 1524 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 1513 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 1525 | } | 1514 | } |
| 1526 | | 1515 | |
| ... | @@ -1540,126 +1529,125 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1540,126 +1529,125 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1540 | | 1529 | |
| 1541 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 1530 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1542 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1531 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1543 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | | |
| 1544 | const src_ty = self.air.typeOf(ty_op.operand); | | |
| 1545 | const src_int_info = src_ty.intInfo(self.target.*); | | |
| 1546 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | | |
| 1547 | const src_mcv = try self.resolveInst(ty_op.operand); | | |
| 1548 | const src_lock = switch (src_mcv) { | | |
| 1549 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1550 | else => null, | | |
| 1551 | }; | | |
| 1552 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1553 | | | |
| 1554 | const dst_ty = self.air.typeOfIndex(inst); | | |
| 1555 | const dst_int_info = dst_ty.intInfo(self.target.*); | | |
| 1556 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | | |
| 1557 | const dst_mcv = if (dst_abi_size <= src_abi_size and | | |
| 1558 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | | |
| 1559 | src_mcv | | |
| 1560 | else | | |
| 1561 | try self.allocRegOrMem(inst, true); | | |
| 1562 | | 1532 | |
| 1563 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; | 1533 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1564 | const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and | 1534 | const src_int_info = src_ty.intInfo(self.target.*); |
| 1565 | src_int_info.signedness == .signed) .signed else .unsigned; | 1535 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 1566 | switch (dst_mcv) { | 1536 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1567 | .register => |dst_reg| { | 1537 | const src_lock = switch (src_mcv) { |
| 1568 | const min_abi_size = @min(dst_abi_size, src_abi_size); | 1538 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1569 | const tag: Mir.Inst.Tag = switch (signedness) { | 1539 | else => null, |
| 1570 | .signed => .movsx, | | |
| 1571 | .unsigned => if (min_abi_size > 2) .mov else .movzx, | | |
| 1572 | }; | | |
| 1573 | const dst_alias = switch (tag) { | | |
| 1574 | .movsx => dst_reg.to64(), | | |
| 1575 | .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(), | | |
| 1576 | else => unreachable, | | |
| 1577 | }; | | |
| 1578 | switch (src_mcv) { | | |
| 1579 | .register => |src_reg| { | | |
| 1580 | try self.asmRegisterRegister( | | |
| 1581 | tag, | | |
| 1582 | dst_alias, | | |
| 1583 | registerAlias(src_reg, min_abi_size), | | |
| 1584 | ); | | |
| 1585 | }, | | |
| 1586 | .stack_offset => |src_off| { | | |
| 1587 | try self.asmRegisterMemory(tag, dst_alias, Memory.sib( | | |
| 1588 | Memory.PtrSize.fromSize(min_abi_size), | | |
| 1589 | .{ .base = .rbp, .disp = -src_off }, | | |
| 1590 | )); | | |
| 1591 | }, | | |
| 1592 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ | | |
| 1593 | @tagName(src_mcv), | | |
| 1594 | @tagName(dst_mcv), | | |
| 1595 | }), | | |
| 1596 | } | | |
| 1597 | if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg); | | |
| 1598 | }, | | |
| 1599 | else => { | | |
| 1600 | try self.setRegOrMem(min_ty, dst_mcv, src_mcv); | | |
| 1601 | const extra = dst_abi_size * 8 - dst_int_info.bits; | | |
| 1602 | if (extra > 0) { | | |
| 1603 | try self.genShiftBinOpMir(switch (signedness) { | | |
| 1604 | .signed => .sal, | | |
| 1605 | .unsigned => .shl, | | |
| 1606 | }, dst_ty, dst_mcv, .{ .immediate = extra }); | | |
| 1607 | try self.genShiftBinOpMir(switch (signedness) { | | |
| 1608 | .signed => .sar, | | |
| 1609 | .unsigned => .shr, | | |
| 1610 | }, dst_ty, dst_mcv, .{ .immediate = extra }); | | |
| 1611 | } | | |
| 1612 | }, | | |
| 1613 | } | | |
| 1614 | break :result dst_mcv; | | |
| 1615 | }; | 1540 | }; |
| 1616 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1541 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1542 | |
| | 1543 | const dst_ty = self.air.typeOfIndex(inst); |
| | 1544 | const dst_int_info = dst_ty.intInfo(self.target.*); |
| | 1545 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| | 1546 | const dst_mcv = if (dst_abi_size <= src_abi_size and |
| | 1547 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| | 1548 | src_mcv |
| | 1549 | else |
| | 1550 | try self.allocRegOrMem(inst, true); |
| | 1551 | |
| | 1552 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| | 1553 | const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and |
| | 1554 | src_int_info.signedness == .signed) .signed else .unsigned; |
| | 1555 | switch (dst_mcv) { |
| | 1556 | .register => |dst_reg| { |
| | 1557 | const min_abi_size = @min(dst_abi_size, src_abi_size); |
| | 1558 | const tag: Mir.Inst.Tag = switch (signedness) { |
| | 1559 | .signed => .movsx, |
| | 1560 | .unsigned => if (min_abi_size > 2) .mov else .movzx, |
| | 1561 | }; |
| | 1562 | const dst_alias = switch (tag) { |
| | 1563 | .movsx => dst_reg.to64(), |
| | 1564 | .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(), |
| | 1565 | else => unreachable, |
| | 1566 | }; |
| | 1567 | switch (src_mcv) { |
| | 1568 | .register => |src_reg| { |
| | 1569 | try self.asmRegisterRegister( |
| | 1570 | tag, |
| | 1571 | dst_alias, |
| | 1572 | registerAlias(src_reg, min_abi_size), |
| | 1573 | ); |
| | 1574 | }, |
| | 1575 | .stack_offset => |src_off| { |
| | 1576 | try self.asmRegisterMemory(tag, dst_alias, Memory.sib( |
| | 1577 | Memory.PtrSize.fromSize(min_abi_size), |
| | 1578 | .{ .base = .rbp, .disp = -src_off }, |
| | 1579 | )); |
| | 1580 | }, |
| | 1581 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ |
| | 1582 | @tagName(src_mcv), |
| | 1583 | @tagName(dst_mcv), |
| | 1584 | }), |
| | 1585 | } |
| | 1586 | if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg); |
| | 1587 | }, |
| | 1588 | else => { |
| | 1589 | try self.setRegOrMem(min_ty, dst_mcv, src_mcv); |
| | 1590 | const extra = dst_abi_size * 8 - dst_int_info.bits; |
| | 1591 | if (extra > 0) { |
| | 1592 | try self.genShiftBinOpMir(switch (signedness) { |
| | 1593 | .signed => .sal, |
| | 1594 | .unsigned => .shl, |
| | 1595 | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| | 1596 | try self.genShiftBinOpMir(switch (signedness) { |
| | 1597 | .signed => .sar, |
| | 1598 | .unsigned => .shr, |
| | 1599 | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| | 1600 | } |
| | 1601 | }, |
| | 1602 | } |
| | 1603 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1617 | } | 1604 | } |
| 1618 | | 1605 | |
| 1619 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1606 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1620 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1607 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1621 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | | |
| 1622 | const dst_ty = self.air.typeOfIndex(inst); | | |
| 1623 | const dst_abi_size = dst_ty.abiSize(self.target.*); | | |
| 1624 | if (dst_abi_size > 8) { | | |
| 1625 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); | | |
| 1626 | } | | |
| 1627 | | | |
| 1628 | const src_mcv = try self.resolveInst(ty_op.operand); | | |
| 1629 | const src_lock = switch (src_mcv) { | | |
| 1630 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1631 | else => null, | | |
| 1632 | }; | | |
| 1633 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1634 | | 1608 | |
| 1635 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 1609 | const dst_ty = self.air.typeOfIndex(inst); |
| 1636 | src_mcv | 1610 | const dst_abi_size = dst_ty.abiSize(self.target.*); |
| 1637 | else | 1611 | if (dst_abi_size > 8) { |
| 1638 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | 1612 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); |
| | 1613 | } |
| 1639 | | 1614 | |
| 1640 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result | 1615 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1641 | // have to be removed. this only happens if the dst if not a power-of-two size. | 1616 | const src_lock = switch (src_mcv) { |
| 1642 | if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); | 1617 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1643 | break :result dst_mcv; | 1618 | else => null, |
| 1644 | }; | 1619 | }; |
| 1645 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1620 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1621 | |
| | 1622 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| | 1623 | src_mcv |
| | 1624 | else |
| | 1625 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| | 1626 | |
| | 1627 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result |
| | 1628 | // have to be removed. this only happens if the dst if not a power-of-two size. |
| | 1629 | if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); |
| | 1630 | |
| | 1631 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1646 | } | 1632 | } |
| 1647 | | 1633 | |
| 1648 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 1634 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1649 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1635 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 1636 | const ty = self.air.typeOfIndex(inst); |
| | 1637 | |
| 1650 | const operand = try self.resolveInst(un_op); | 1638 | const operand = try self.resolveInst(un_op); |
| 1651 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else operand; | 1639 | const dst_mcv = if (self.reuseOperand(inst, un_op, 0, operand)) |
| 1652 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1640 | operand |
| | 1641 | else |
| | 1642 | try self.copyToRegisterWithInstTracking(inst, ty, operand); |
| | 1643 | |
| | 1644 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 1653 | } | 1645 | } |
| 1654 | | 1646 | |
| 1655 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 1647 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1656 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1648 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1657 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1649 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1658 | | 1650 | |
| 1659 | if (self.liveness.isUnused(inst)) { | | |
| 1660 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1661 | } | | |
| 1662 | | | |
| 1663 | const ptr = try self.resolveInst(bin_op.lhs); | 1651 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1664 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 1652 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 1665 | const len = try self.resolveInst(bin_op.rhs); | 1653 | const len = try self.resolveInst(bin_op.rhs); |
| ... | @@ -1675,33 +1663,21 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1675,33 +1663,21 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1675 | | 1663 | |
| 1676 | fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1664 | fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1677 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1665 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1678 | | 1666 | const dst_mcv = try self.genUnOp(inst, tag, ty_op.operand); |
| 1679 | const result = if (self.liveness.isUnused(inst)) | 1667 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1680 | .unreach | | |
| 1681 | else | | |
| 1682 | try self.genUnOp(inst, tag, ty_op.operand); | | |
| 1683 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 1684 | } | 1668 | } |
| 1685 | | 1669 | |
| 1686 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1670 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1687 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1671 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1688 | | 1672 | const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1689 | const result = if (self.liveness.isUnused(inst)) | 1673 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1690 | .unreach | | |
| 1691 | else | | |
| 1692 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | | |
| 1693 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1694 | } | 1674 | } |
| 1695 | | 1675 | |
| 1696 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1676 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1697 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1677 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1698 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1678 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1699 | | 1679 | const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1700 | const result = if (self.liveness.isUnused(inst)) | 1680 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1701 | .unreach | | |
| 1702 | else | | |
| 1703 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | | |
| 1704 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1705 | } | 1681 | } |
| 1706 | | 1682 | |
| 1707 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { | 1683 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| ... | @@ -1741,7 +1717,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { | ... | @@ -1741,7 +1717,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 1741 | | 1717 | |
| 1742 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1718 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1743 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1719 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1744 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 1720 | const result = result: { |
| 1745 | const tag = self.air.instructions.items(.tag)[inst]; | 1721 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1746 | const dst_ty = self.air.typeOfIndex(inst); | 1722 | const dst_ty = self.air.typeOfIndex(inst); |
| 1747 | if (dst_ty.zigTypeTag() == .Float) | 1723 | if (dst_ty.zigTypeTag() == .Float) |
| ... | @@ -1772,168 +1748,162 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1772,168 +1748,162 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1772 | | 1748 | |
| 1773 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | 1749 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1774 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1750 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1775 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 1751 | const ty = self.air.typeOf(bin_op.lhs); |
| 1776 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 1777 | | 1752 | |
| 1778 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 1753 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1779 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) | 1754 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1780 | lhs_mcv | 1755 | lhs_mcv |
| 1781 | else | 1756 | else |
| 1782 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); | 1757 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1783 | const dst_reg = dst_mcv.register; | 1758 | const dst_reg = dst_mcv.register; |
| 1784 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 1759 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1785 | defer self.register_manager.unlockReg(dst_lock); | 1760 | defer self.register_manager.unlockReg(dst_lock); |
| 1786 | | 1761 | |
| 1787 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 1762 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1788 | const rhs_lock = switch (rhs_mcv) { | 1763 | const rhs_lock = switch (rhs_mcv) { |
| 1789 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1764 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1790 | else => null, | 1765 | else => null, |
| 1791 | }; | 1766 | }; |
| 1792 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 1767 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1793 | | | |
| 1794 | const limit_reg = try self.register_manager.allocReg(null, gp); | | |
| 1795 | const limit_mcv = MCValue{ .register = limit_reg }; | | |
| 1796 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); | | |
| 1797 | defer self.register_manager.unlockReg(limit_lock); | | |
| 1798 | | | |
| 1799 | const reg_bits = self.regBitSize(ty); | | |
| 1800 | const cc: Condition = if (ty.isSignedInt()) cc: { | | |
| 1801 | try self.genSetReg(ty, limit_reg, dst_mcv); | | |
| 1802 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | | |
| 1803 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ | | |
| 1804 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, | | |
| 1805 | }); | | |
| 1806 | break :cc .o; | | |
| 1807 | } else cc: { | | |
| 1808 | try self.genSetReg(ty, limit_reg, .{ | | |
| 1809 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), | | |
| 1810 | }); | | |
| 1811 | break :cc .c; | | |
| 1812 | }; | | |
| 1813 | try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv); | | |
| 1814 | | 1768 | |
| 1815 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 1769 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1816 | try self.asmCmovccRegisterRegister( | 1770 | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1817 | registerAlias(dst_reg, cmov_abi_size), | 1771 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1818 | registerAlias(limit_reg, cmov_abi_size), | 1772 | defer self.register_manager.unlockReg(limit_lock); |
| 1819 | cc, | 1773 | |
| 1820 | ); | 1774 | const reg_bits = self.regBitSize(ty); |
| 1821 | break :result dst_mcv; | 1775 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 1776 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| | 1777 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1778 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1779 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1780 | }); |
| | 1781 | break :cc .o; |
| | 1782 | } else cc: { |
| | 1783 | try self.genSetReg(ty, limit_reg, .{ |
| | 1784 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| | 1785 | }); |
| | 1786 | break :cc .c; |
| 1822 | }; | 1787 | }; |
| 1823 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1788 | try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv); |
| | 1789 | |
| | 1790 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| | 1791 | try self.asmCmovccRegisterRegister( |
| | 1792 | registerAlias(dst_reg, cmov_abi_size), |
| | 1793 | registerAlias(limit_reg, cmov_abi_size), |
| | 1794 | cc, |
| | 1795 | ); |
| | 1796 | |
| | 1797 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1824 | } | 1798 | } |
| 1825 | | 1799 | |
| 1826 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | 1800 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1827 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1801 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1828 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 1802 | const ty = self.air.typeOf(bin_op.lhs); |
| 1829 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 1830 | | | |
| 1831 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | | |
| 1832 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) | | |
| 1833 | lhs_mcv | | |
| 1834 | else | | |
| 1835 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); | | |
| 1836 | const dst_reg = dst_mcv.register; | | |
| 1837 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | | |
| 1838 | defer self.register_manager.unlockReg(dst_lock); | | |
| 1839 | | 1803 | |
| 1840 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 1804 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1841 | const rhs_lock = switch (rhs_mcv) { | 1805 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1842 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1806 | lhs_mcv |
| 1843 | else => null, | 1807 | else |
| 1844 | }; | 1808 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1845 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 1809 | const dst_reg = dst_mcv.register; |
| 1846 | | 1810 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1847 | const limit_reg = try self.register_manager.allocReg(null, gp); | 1811 | defer self.register_manager.unlockReg(dst_lock); |
| 1848 | const limit_mcv = MCValue{ .register = limit_reg }; | | |
| 1849 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); | | |
| 1850 | defer self.register_manager.unlockReg(limit_lock); | | |
| 1851 | | | |
| 1852 | const reg_bits = self.regBitSize(ty); | | |
| 1853 | const cc: Condition = if (ty.isSignedInt()) cc: { | | |
| 1854 | try self.genSetReg(ty, limit_reg, dst_mcv); | | |
| 1855 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | | |
| 1856 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ | | |
| 1857 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, | | |
| 1858 | }); | | |
| 1859 | break :cc .o; | | |
| 1860 | } else cc: { | | |
| 1861 | try self.genSetReg(ty, limit_reg, .{ .immediate = 0 }); | | |
| 1862 | break :cc .c; | | |
| 1863 | }; | | |
| 1864 | try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv); | | |
| 1865 | | 1812 | |
| 1866 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 1813 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1867 | try self.asmCmovccRegisterRegister( | 1814 | const rhs_lock = switch (rhs_mcv) { |
| 1868 | registerAlias(dst_reg, cmov_abi_size), | 1815 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1869 | registerAlias(limit_reg, cmov_abi_size), | 1816 | else => null, |
| 1870 | cc, | | |
| 1871 | ); | | |
| 1872 | break :result dst_mcv; | | |
| 1873 | }; | 1817 | }; |
| 1874 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1818 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1819 | |
| | 1820 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| | 1821 | const limit_mcv = MCValue{ .register = limit_reg }; |
| | 1822 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| | 1823 | defer self.register_manager.unlockReg(limit_lock); |
| | 1824 | |
| | 1825 | const reg_bits = self.regBitSize(ty); |
| | 1826 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| | 1827 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| | 1828 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1829 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1830 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1831 | }); |
| | 1832 | break :cc .o; |
| | 1833 | } else cc: { |
| | 1834 | try self.genSetReg(ty, limit_reg, .{ .immediate = 0 }); |
| | 1835 | break :cc .c; |
| | 1836 | }; |
| | 1837 | try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv); |
| | 1838 | |
| | 1839 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| | 1840 | try self.asmCmovccRegisterRegister( |
| | 1841 | registerAlias(dst_reg, cmov_abi_size), |
| | 1842 | registerAlias(limit_reg, cmov_abi_size), |
| | 1843 | cc, |
| | 1844 | ); |
| | 1845 | |
| | 1846 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1875 | } | 1847 | } |
| 1876 | | 1848 | |
| 1877 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | 1849 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1878 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1850 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1879 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 1851 | const ty = self.air.typeOf(bin_op.lhs); |
| 1880 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 1881 | | 1852 | |
| 1882 | try self.spillRegisters(&.{ .rax, .rdx }); | 1853 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 1883 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 1854 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 1884 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 1855 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 1885 | | 1856 | |
| 1886 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 1857 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1887 | const lhs_lock = switch (lhs_mcv) { | 1858 | const lhs_lock = switch (lhs_mcv) { |
| 1888 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1859 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1889 | else => null, | 1860 | else => null, |
| 1890 | }; | 1861 | }; |
| 1891 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 1862 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1892 | | 1863 | |
| 1893 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 1864 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1894 | const rhs_lock = switch (rhs_mcv) { | 1865 | const rhs_lock = switch (rhs_mcv) { |
| 1895 | .register => |reg| self.register_manager.lockReg(reg), | 1866 | .register => |reg| self.register_manager.lockReg(reg), |
| 1896 | else => null, | 1867 | else => null, |
| 1897 | }; | 1868 | }; |
| 1898 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 1869 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1899 | | | |
| 1900 | const limit_reg = try self.register_manager.allocReg(null, gp); | | |
| 1901 | const limit_mcv = MCValue{ .register = limit_reg }; | | |
| 1902 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); | | |
| 1903 | defer self.register_manager.unlockReg(limit_lock); | | |
| 1904 | | | |
| 1905 | const reg_bits = self.regBitSize(ty); | | |
| 1906 | const cc: Condition = if (ty.isSignedInt()) cc: { | | |
| 1907 | try self.genSetReg(ty, limit_reg, lhs_mcv); | | |
| 1908 | try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv); | | |
| 1909 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | | |
| 1910 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ | | |
| 1911 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, | | |
| 1912 | }); | | |
| 1913 | break :cc .o; | | |
| 1914 | } else cc: { | | |
| 1915 | try self.genSetReg(ty, limit_reg, .{ | | |
| 1916 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), | | |
| 1917 | }); | | |
| 1918 | break :cc .c; | | |
| 1919 | }; | | |
| 1920 | | 1870 | |
| 1921 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); | 1871 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1922 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 1872 | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1923 | try self.asmCmovccRegisterRegister( | 1873 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1924 | registerAlias(dst_mcv.register, cmov_abi_size), | 1874 | defer self.register_manager.unlockReg(limit_lock); |
| 1925 | registerAlias(limit_reg, cmov_abi_size), | 1875 | |
| 1926 | cc, | 1876 | const reg_bits = self.regBitSize(ty); |
| 1927 | ); | 1877 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1928 | break :result dst_mcv; | 1878 | try self.genSetReg(ty, limit_reg, lhs_mcv); |
| | 1879 | try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv); |
| | 1880 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| | 1881 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| | 1882 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| | 1883 | }); |
| | 1884 | break :cc .o; |
| | 1885 | } else cc: { |
| | 1886 | try self.genSetReg(ty, limit_reg, .{ |
| | 1887 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| | 1888 | }); |
| | 1889 | break :cc .c; |
| 1929 | }; | 1890 | }; |
| 1930 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1891 | |
| | 1892 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); |
| | 1893 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| | 1894 | try self.asmCmovccRegisterRegister( |
| | 1895 | registerAlias(dst_mcv.register, cmov_abi_size), |
| | 1896 | registerAlias(limit_reg, cmov_abi_size), |
| | 1897 | cc, |
| | 1898 | ); |
| | 1899 | |
| | 1900 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1931 | } | 1901 | } |
| 1932 | | 1902 | |
| 1933 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1903 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1934 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1904 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1935 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1905 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1936 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 1906 | const result: MCValue = result: { |
| 1937 | const tag = self.air.instructions.items(.tag)[inst]; | 1907 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1938 | const ty = self.air.typeOf(bin_op.lhs); | 1908 | const ty = self.air.typeOf(bin_op.lhs); |
| 1939 | switch (ty.zigTypeTag()) { | 1909 | switch (ty.zigTypeTag()) { |
| ... | @@ -1992,7 +1962,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1992,7 +1962,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1992 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1962 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1993 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1963 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1994 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1964 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1995 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 1965 | const result: MCValue = result: { |
| 1996 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1966 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1997 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1967 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1998 | switch (lhs_ty.zigTypeTag()) { | 1968 | switch (lhs_ty.zigTypeTag()) { |
| ... | @@ -2114,7 +2084,7 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -2114,7 +2084,7 @@ fn genSetStackTruncatedOverflowCompare( |
| 2114 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 2084 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2115 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2085 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2116 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2086 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2117 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 2087 | const result: MCValue = result: { |
| 2118 | const dst_ty = self.air.typeOf(bin_op.lhs); | 2088 | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 2119 | switch (dst_ty.zigTypeTag()) { | 2089 | switch (dst_ty.zigTypeTag()) { |
| 2120 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 2090 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| ... | @@ -2303,10 +2273,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -2303,10 +2273,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 2303 | fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { | 2273 | fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2304 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2274 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2305 | | 2275 | |
| 2306 | if (self.liveness.isUnused(inst)) { | | |
| 2307 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2308 | } | | |
| 2309 | | | |
| 2310 | try self.spillRegisters(&.{.rcx}); | 2276 | try self.spillRegisters(&.{.rcx}); |
| 2311 | | 2277 | |
| 2312 | const tag = self.air.instructions.items(.tag)[inst]; | 2278 | const tag = self.air.instructions.items(.tag)[inst]; |
| ... | @@ -2323,18 +2289,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2323,18 +2289,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2323 | | 2289 | |
| 2324 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | 2290 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2325 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2291 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2326 | const result: MCValue = if (self.liveness.isUnused(inst)) | 2292 | _ = bin_op; |
| 2327 | .unreach | 2293 | return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 2328 | else | 2294 | //return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2329 | return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); | | |
| 2330 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2331 | } | 2295 | } |
| 2332 | | 2296 | |
| 2333 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 2297 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2334 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2298 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2335 | const result: MCValue = result: { | 2299 | const result: MCValue = result: { |
| 2336 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2337 | | | |
| 2338 | const pl_ty = self.air.typeOfIndex(inst); | 2300 | const pl_ty = self.air.typeOfIndex(inst); |
| 2339 | const opt_mcv = try self.resolveInst(ty_op.operand); | 2301 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2340 | | 2302 | |
| ... | @@ -2359,18 +2321,15 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2359,18 +2321,15 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2359 | | 2321 | |
| 2360 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | 2322 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2361 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2323 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2362 | const result: MCValue = result: { | | |
| 2363 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2364 | | 2324 | |
| 2365 | const dst_ty = self.air.typeOfIndex(inst); | 2325 | const dst_ty = self.air.typeOfIndex(inst); |
| 2366 | const opt_mcv = try self.resolveInst(ty_op.operand); | 2326 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2367 | | 2327 | |
| 2368 | break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) | 2328 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2369 | opt_mcv | 2329 | opt_mcv |
| 2370 | else | 2330 | else |
| 2371 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); | 2331 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2372 | }; | 2332 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2373 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 2374 | } | 2333 | } |
| 2375 | | 2334 | |
| 2376 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | 2335 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2409,9 +2368,6 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2409,9 +2368,6 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2409 | | 2368 | |
| 2410 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 2369 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2411 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2370 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2412 | if (self.liveness.isUnused(inst)) { | | |
| 2413 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 2414 | } | | |
| 2415 | const err_union_ty = self.air.typeOf(ty_op.operand); | 2371 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 2416 | const err_ty = err_union_ty.errorUnionSet(); | 2372 | const err_ty = err_union_ty.errorUnionSet(); |
| 2417 | const payload_ty = err_union_ty.errorUnionPayload(); | 2373 | const payload_ty = err_union_ty.errorUnionPayload(); |
| ... | @@ -2454,9 +2410,6 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2454,9 +2410,6 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2454 | | 2410 | |
| 2455 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 2411 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2456 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2412 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2457 | if (self.liveness.isUnused(inst)) { | | |
| 2458 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 2459 | } | | |
| 2460 | const err_union_ty = self.air.typeOf(ty_op.operand); | 2413 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 2461 | const operand = try self.resolveInst(ty_op.operand); | 2414 | const operand = try self.resolveInst(ty_op.operand); |
| 2462 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); | 2415 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); |
| ... | @@ -2507,72 +2460,68 @@ fn genUnwrapErrorUnionPayloadMir( | ... | @@ -2507,72 +2460,68 @@ fn genUnwrapErrorUnionPayloadMir( |
| 2507 | // *(E!T) -> E | 2460 | // *(E!T) -> E |
| 2508 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 2461 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2509 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2462 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2510 | const result: MCValue = result: { | | |
| 2511 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2512 | | 2463 | |
| 2513 | const src_ty = self.air.typeOf(ty_op.operand); | 2464 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2514 | const src_mcv = try self.resolveInst(ty_op.operand); | 2465 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2515 | const src_reg = switch (src_mcv) { | 2466 | const src_reg = switch (src_mcv) { |
| 2516 | .register => |reg| reg, | 2467 | .register => |reg| reg, |
| 2517 | else => try self.copyToTmpRegister(src_ty, src_mcv), | 2468 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2518 | }; | 2469 | }; |
| 2519 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 2470 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2520 | defer self.register_manager.unlockReg(src_lock); | 2471 | defer self.register_manager.unlockReg(src_lock); |
| 2521 | | 2472 | |
| 2522 | const dst_reg = try self.register_manager.allocReg(inst, gp); | 2473 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 2523 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 2474 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2524 | defer self.register_manager.unlockReg(dst_lock); | 2475 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| | 2476 | defer self.register_manager.unlockReg(dst_lock); |
| 2525 | | 2477 | |
| 2526 | const eu_ty = src_ty.childType(); | 2478 | const eu_ty = src_ty.childType(); |
| 2527 | const pl_ty = eu_ty.errorUnionPayload(); | 2479 | const pl_ty = eu_ty.errorUnionPayload(); |
| 2528 | const err_ty = eu_ty.errorUnionSet(); | 2480 | const err_ty = eu_ty.errorUnionSet(); |
| 2529 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | 2481 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); |
| 2530 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); | 2482 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); |
| 2531 | try self.asmRegisterMemory( | 2483 | try self.asmRegisterMemory( |
| 2532 | .mov, | 2484 | .mov, |
| 2533 | registerAlias(dst_reg, err_abi_size), | 2485 | registerAlias(dst_reg, err_abi_size), |
| 2534 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }), | 2486 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }), |
| 2535 | ); | 2487 | ); |
| 2536 | break :result .{ .register = dst_reg }; | 2488 | |
| 2537 | }; | 2489 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2538 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 2539 | } | 2490 | } |
| 2540 | | 2491 | |
| 2541 | // *(E!T) -> *T | 2492 | // *(E!T) -> *T |
| 2542 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | 2493 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2543 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2494 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2544 | const result: MCValue = result: { | | |
| 2545 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2546 | | 2495 | |
| 2547 | const src_ty = self.air.typeOf(ty_op.operand); | 2496 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2548 | const src_mcv = try self.resolveInst(ty_op.operand); | 2497 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2549 | const src_reg = switch (src_mcv) { | 2498 | const src_reg = switch (src_mcv) { |
| 2550 | .register => |reg| reg, | 2499 | .register => |reg| reg, |
| 2551 | else => try self.copyToTmpRegister(src_ty, src_mcv), | 2500 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2552 | }; | 2501 | }; |
| 2553 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 2502 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2554 | defer self.register_manager.unlockReg(src_lock); | 2503 | defer self.register_manager.unlockReg(src_lock); |
| 2555 | | 2504 | |
| 2556 | const dst_ty = self.air.typeOfIndex(inst); | 2505 | const dst_ty = self.air.typeOfIndex(inst); |
| 2557 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 2506 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2558 | src_reg | 2507 | src_reg |
| 2559 | else | 2508 | else |
| 2560 | try self.register_manager.allocReg(inst, gp); | 2509 | try self.register_manager.allocReg(inst, gp); |
| 2561 | const dst_lock = self.register_manager.lockReg(dst_reg); | 2510 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2562 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 2511 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| | 2512 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2563 | | 2513 | |
| 2564 | const eu_ty = src_ty.childType(); | 2514 | const eu_ty = src_ty.childType(); |
| 2565 | const pl_ty = eu_ty.errorUnionPayload(); | 2515 | const pl_ty = eu_ty.errorUnionPayload(); |
| 2566 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | 2516 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); |
| 2567 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 2517 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2568 | try self.asmRegisterMemory( | 2518 | try self.asmRegisterMemory( |
| 2569 | .lea, | 2519 | .lea, |
| 2570 | registerAlias(dst_reg, dst_abi_size), | 2520 | registerAlias(dst_reg, dst_abi_size), |
| 2571 | Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }), | 2521 | Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }), |
| 2572 | ); | 2522 | ); |
| 2573 | break :result .{ .register = dst_reg }; | 2523 | |
| 2574 | }; | 2524 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2575 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 2576 | } | 2525 | } |
| 2577 | | 2526 | |
| 2578 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | 2527 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2621,11 +2570,9 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2621,11 +2570,9 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2621 | } | 2570 | } |
| 2622 | | 2571 | |
| 2623 | fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { | 2572 | fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 2624 | const result: MCValue = if (self.liveness.isUnused(inst)) | 2573 | _ = inst; |
| 2625 | .unreach | 2574 | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 2626 | else | 2575 | //return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 2627 | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); | | |
| 2628 | return self.finishAir(inst, result, .{ .none, .none, .none }); | | |
| 2629 | } | 2576 | } |
| 2630 | | 2577 | |
| 2631 | fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { | 2578 | fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2641,8 +2588,6 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2641,8 +2588,6 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 2641 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 2588 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2642 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2589 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2643 | const result: MCValue = result: { | 2590 | const result: MCValue = result: { |
| 2644 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2645 | | | |
| 2646 | const pl_ty = self.air.typeOf(ty_op.operand); | 2591 | const pl_ty = self.air.typeOf(ty_op.operand); |
| 2647 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; | 2592 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; |
| 2648 | | 2593 | |
| ... | @@ -2687,10 +2632,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2687,10 +2632,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2687 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 2632 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2688 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2633 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2689 | | 2634 | |
| 2690 | if (self.liveness.isUnused(inst)) { | | |
| 2691 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 2692 | } | | |
| 2693 | | | |
| 2694 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2635 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2695 | const payload_ty = error_union_ty.errorUnionPayload(); | 2636 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2696 | const operand = try self.resolveInst(ty_op.operand); | 2637 | const operand = try self.resolveInst(ty_op.operand); |
| ... | @@ -2717,9 +2658,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2717,9 +2658,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2717 | /// E to E!T | 2658 | /// E to E!T |
| 2718 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 2659 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2719 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2660 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2720 | if (self.liveness.isUnused(inst)) { | 2661 | |
| 2721 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 2722 | } | | |
| 2723 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2662 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2724 | const payload_ty = error_union_ty.errorUnionPayload(); | 2663 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2725 | const operand = try self.resolveInst(ty_op.operand); | 2664 | const operand = try self.resolveInst(ty_op.operand); |
| ... | @@ -2745,7 +2684,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2745,7 +2684,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2745 | | 2684 | |
| 2746 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 2685 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2747 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2686 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2748 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 2687 | const result = result: { |
| 2749 | const src_mcv = try self.resolveInst(ty_op.operand); | 2688 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2750 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 2689 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 2751 | | 2690 | |
| ... | @@ -2759,72 +2698,65 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2759,72 +2698,65 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2759 | | 2698 | |
| 2760 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | 2699 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2761 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2700 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2762 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 2701 | |
| 2763 | const operand = try self.resolveInst(ty_op.operand); | 2702 | const operand = try self.resolveInst(ty_op.operand); |
| 2764 | const dst_mcv: MCValue = blk: { | 2703 | const dst_mcv: MCValue = blk: { |
| 2765 | switch (operand) { | 2704 | switch (operand) { |
| 2766 | .stack_offset => |off| { | 2705 | .stack_offset => |off| { |
| 2767 | break :blk MCValue{ .stack_offset = off - 8 }; | 2706 | break :blk MCValue{ .stack_offset = off - 8 }; |
| 2768 | }, | 2707 | }, |
| 2769 | else => return self.fail("TODO implement slice_len for {}", .{operand}), | 2708 | else => return self.fail("TODO implement slice_len for {}", .{operand}), |
| 2770 | } | 2709 | } |
| 2771 | }; | | |
| 2772 | break :result dst_mcv; | | |
| 2773 | }; | 2710 | }; |
| 2774 | log.debug("airSliceLen(%{d}): {}", .{ inst, result }); | 2711 | |
| 2775 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2712 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2776 | } | 2713 | } |
| 2777 | | 2714 | |
| 2778 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | 2715 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2779 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2716 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2780 | const result: MCValue = result: { | | |
| 2781 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2782 | | 2717 | |
| 2783 | const src_ty = self.air.typeOf(ty_op.operand); | 2718 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2784 | const src_mcv = try self.resolveInst(ty_op.operand); | 2719 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2785 | const src_reg = switch (src_mcv) { | 2720 | const src_reg = switch (src_mcv) { |
| 2786 | .register => |reg| reg, | 2721 | .register => |reg| reg, |
| 2787 | else => try self.copyToTmpRegister(src_ty, src_mcv), | 2722 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2788 | }; | 2723 | }; |
| 2789 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 2724 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2790 | defer self.register_manager.unlockReg(src_lock); | 2725 | defer self.register_manager.unlockReg(src_lock); |
| 2791 | | 2726 | |
| 2792 | const dst_ty = self.air.typeOfIndex(inst); | 2727 | const dst_ty = self.air.typeOfIndex(inst); |
| 2793 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 2728 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2794 | src_reg | 2729 | src_reg |
| 2795 | else | 2730 | else |
| 2796 | try self.register_manager.allocReg(inst, gp); | 2731 | try self.register_manager.allocReg(inst, gp); |
| 2797 | const dst_lock = self.register_manager.lockReg(dst_reg); | 2732 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2798 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 2733 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| | 2734 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2799 | | 2735 | |
| 2800 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 2736 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2801 | try self.asmRegisterMemory( | 2737 | try self.asmRegisterMemory( |
| 2802 | .lea, | 2738 | .lea, |
| 2803 | registerAlias(dst_reg, dst_abi_size), | 2739 | registerAlias(dst_reg, dst_abi_size), |
| 2804 | Memory.sib(.qword, .{ | 2740 | Memory.sib(.qword, .{ |
| 2805 | .base = src_reg, | 2741 | .base = src_reg, |
| 2806 | .disp = @divExact(self.target.cpu.arch.ptrBitWidth(), 8), | 2742 | .disp = @divExact(self.target.cpu.arch.ptrBitWidth(), 8), |
| 2807 | }), | 2743 | }), |
| 2808 | ); | 2744 | ); |
| 2809 | break :result .{ .register = dst_reg }; | 2745 | |
| 2810 | }; | 2746 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2811 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 2812 | } | 2747 | } |
| 2813 | | 2748 | |
| 2814 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | 2749 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2815 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2750 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2816 | const result: MCValue = result: { | | |
| 2817 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 2818 | | 2751 | |
| 2819 | const dst_ty = self.air.typeOfIndex(inst); | 2752 | const dst_ty = self.air.typeOfIndex(inst); |
| 2820 | const opt_mcv = try self.resolveInst(ty_op.operand); | 2753 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2821 | | 2754 | |
| 2822 | break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) | 2755 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2823 | opt_mcv | 2756 | opt_mcv |
| 2824 | else | 2757 | else |
| 2825 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); | 2758 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2826 | }; | 2759 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2827 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 2828 | } | 2760 | } |
| 2829 | | 2761 | |
| 2830 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { | 2762 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| ... | @@ -2892,34 +2824,26 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | ... | @@ -2892,34 +2824,26 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2892 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2824 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2893 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2825 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2894 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2826 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 2895 | const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: { | 2827 | |
| 2896 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2828 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2897 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 2829 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 2898 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); | 2830 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 2899 | const dst_mcv = try self.allocRegOrMem(inst, false); | 2831 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2900 | try self.load(dst_mcv, elem_ptr, slice_ptr_field_type); | 2832 | try self.load(dst_mcv, elem_ptr, slice_ptr_field_type); |
| 2901 | break :result dst_mcv; | 2833 | |
| 2902 | }; | 2834 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2903 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2904 | } | 2835 | } |
| 2905 | | 2836 | |
| 2906 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 2837 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2907 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2838 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2908 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2839 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2909 | const result: MCValue = if (self.liveness.isUnused(inst)) | 2840 | const dst_mcv = try self.genSliceElemPtr(extra.lhs, extra.rhs); |
| 2910 | .unreach | 2841 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 2911 | else | | |
| 2912 | try self.genSliceElemPtr(extra.lhs, extra.rhs); | | |
| 2913 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | | |
| 2914 | } | 2842 | } |
| 2915 | | 2843 | |
| 2916 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2844 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2917 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2845 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2918 | | 2846 | |
| 2919 | if (self.liveness.isUnused(inst)) { | | |
| 2920 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2921 | } | | |
| 2922 | | | |
| 2923 | const array_ty = self.air.typeOf(bin_op.lhs); | 2847 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 2924 | const array = try self.resolveInst(bin_op.lhs); | 2848 | const array = try self.resolveInst(bin_op.lhs); |
| 2925 | const array_lock: ?RegisterLock = switch (array) { | 2849 | const array_lock: ?RegisterLock = switch (array) { |
| ... | @@ -2986,77 +2910,74 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2986,77 +2910,74 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2986 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2910 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2987 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2911 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2988 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2912 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2989 | const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: { | | |
| 2990 | // this is identical to the `airPtrElemPtr` codegen expect here an | | |
| 2991 | // additional `mov` is needed at the end to get the actual value | | |
| 2992 | | | |
| 2993 | const elem_ty = ptr_ty.elemType2(); | | |
| 2994 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | | |
| 2995 | const index_ty = self.air.typeOf(bin_op.rhs); | | |
| 2996 | const index_mcv = try self.resolveInst(bin_op.rhs); | | |
| 2997 | const index_lock = switch (index_mcv) { | | |
| 2998 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2999 | else => null, | | |
| 3000 | }; | | |
| 3001 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3002 | | 2913 | |
| 3003 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); | 2914 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 3004 | const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2915 | // additional `mov` is needed at the end to get the actual value |
| 3005 | defer self.register_manager.unlockReg(offset_lock); | | |
| 3006 | | 2916 | |
| 3007 | const ptr_mcv = try self.resolveInst(bin_op.lhs); | 2917 | const elem_ty = ptr_ty.elemType2(); |
| 3008 | const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0)) | 2918 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| 3009 | ptr_mcv.register | 2919 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 3010 | else | 2920 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 3011 | try self.copyToTmpRegister(ptr_ty, ptr_mcv); | 2921 | const index_lock = switch (index_mcv) { |
| 3012 | const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg); | 2922 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3013 | defer self.register_manager.unlockReg(elem_ptr_lock); | 2923 | else => null, |
| 3014 | try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg); | 2924 | }; |
| | 2925 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 3015 | | 2926 | |
| 3016 | const dst_mcv = try self.allocRegOrMem(inst, true); | 2927 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); |
| 3017 | const dst_lock = switch (dst_mcv) { | 2928 | const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3018 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2929 | defer self.register_manager.unlockReg(offset_lock); |
| 3019 | else => null, | 2930 | |
| 3020 | }; | 2931 | const ptr_mcv = try self.resolveInst(bin_op.lhs); |
| 3021 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 2932 | const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0)) |
| 3022 | try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty); | 2933 | ptr_mcv.register |
| 3023 | break :result dst_mcv; | 2934 | else |
| | 2935 | try self.copyToTmpRegister(ptr_ty, ptr_mcv); |
| | 2936 | const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg); |
| | 2937 | defer self.register_manager.unlockReg(elem_ptr_lock); |
| | 2938 | try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg); |
| | 2939 | |
| | 2940 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 2941 | const dst_lock = switch (dst_mcv) { |
| | 2942 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 2943 | else => null, |
| 3024 | }; | 2944 | }; |
| 3025 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2945 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2946 | try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty); |
| | 2947 | |
| | 2948 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3026 | } | 2949 | } |
| 3027 | | 2950 | |
| 3028 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 2951 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3029 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2952 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3030 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2953 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3031 | | 2954 | |
| 3032 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 2955 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 3033 | const ptr_ty = self.air.typeOf(extra.lhs); | 2956 | const ptr = try self.resolveInst(extra.lhs); |
| 3034 | const ptr = try self.resolveInst(extra.lhs); | 2957 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 3035 | const ptr_lock: ?RegisterLock = switch (ptr) { | 2958 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3036 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2959 | else => null, |
| 3037 | else => null, | 2960 | }; |
| 3038 | }; | 2961 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 3039 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3040 | | 2962 | |
| 3041 | const elem_ty = ptr_ty.elemType2(); | 2963 | const elem_ty = ptr_ty.elemType2(); |
| 3042 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 2964 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 3043 | const index_ty = self.air.typeOf(extra.rhs); | 2965 | const index_ty = self.air.typeOf(extra.rhs); |
| 3044 | const index = try self.resolveInst(extra.rhs); | 2966 | const index = try self.resolveInst(extra.rhs); |
| 3045 | const index_lock: ?RegisterLock = switch (index) { | 2967 | const index_lock: ?RegisterLock = switch (index) { |
| 3046 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2968 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3047 | else => null, | 2969 | else => null, |
| 3048 | }; | 2970 | }; |
| 3049 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); | 2971 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2972 | |
| | 2973 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| | 2974 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| | 2975 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3050 | | 2976 | |
| 3051 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 2977 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 3052 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2978 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 3053 | defer self.register_manager.unlockReg(offset_reg_lock); | | |
| 3054 | | 2979 | |
| 3055 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); | 2980 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 3056 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); | | |
| 3057 | break :result dst_mcv; | | |
| 3058 | }; | | |
| 3059 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | | |
| 3060 | } | 2981 | } |
| 3061 | | 2982 | |
| 3062 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 2983 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -3098,9 +3019,6 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3098,9 +3019,6 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3098 | | 3019 | |
| 3099 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 3020 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3100 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3021 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3101 | if (self.liveness.isUnused(inst)) { | | |
| 3102 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 3103 | } | | |
| 3104 | | 3022 | |
| 3105 | const tag_ty = self.air.typeOfIndex(inst); | 3023 | const tag_ty = self.air.typeOfIndex(inst); |
| 3106 | const union_ty = self.air.typeOf(ty_op.operand); | 3024 | const union_ty = self.air.typeOf(ty_op.operand); |
| ... | @@ -3152,8 +3070,6 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3152,8 +3070,6 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3152 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { | 3070 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 3153 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3071 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3154 | const result = result: { | 3072 | const result = result: { |
| 3155 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 3156 | | | |
| 3157 | const dst_ty = self.air.typeOfIndex(inst); | 3073 | const dst_ty = self.air.typeOfIndex(inst); |
| 3158 | const src_ty = self.air.typeOf(ty_op.operand); | 3074 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3159 | | 3075 | |
| ... | @@ -3221,8 +3137,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3221,8 +3137,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 3221 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | 3137 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 3222 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3138 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3223 | const result = result: { | 3139 | const result = result: { |
| 3224 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 3225 | | | |
| 3226 | const dst_ty = self.air.typeOfIndex(inst); | 3140 | const dst_ty = self.air.typeOfIndex(inst); |
| 3227 | const src_ty = self.air.typeOf(ty_op.operand); | 3141 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3228 | const src_bits = src_ty.bitSize(self.target.*); | 3142 | const src_bits = src_ty.bitSize(self.target.*); |
| ... | @@ -3279,8 +3193,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3279,8 +3193,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 3279 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | 3193 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 3280 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3194 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3281 | const result: MCValue = result: { | 3195 | const result: MCValue = result: { |
| 3282 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 3283 | | | |
| 3284 | const src_ty = self.air.typeOf(ty_op.operand); | 3196 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3285 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 3197 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 3286 | const src_mcv = try self.resolveInst(ty_op.operand); | 3198 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | @@ -3449,148 +3361,138 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m | ... | @@ -3449,148 +3361,138 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m |
| 3449 | | 3361 | |
| 3450 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | 3362 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 3451 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3363 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3452 | const result = result: { | | |
| 3453 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 3454 | | 3364 | |
| 3455 | const src_ty = self.air.typeOf(ty_op.operand); | 3365 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3456 | const src_mcv = try self.resolveInst(ty_op.operand); | 3366 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3457 | | 3367 | |
| 3458 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); | 3368 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); |
| 3459 | switch (self.regExtraBits(src_ty)) { | 3369 | switch (self.regExtraBits(src_ty)) { |
| 3460 | 0 => {}, | 3370 | 0 => {}, |
| 3461 | else => |extra| try self.genBinOpMir( | 3371 | else => |extra| try self.genBinOpMir( |
| 3462 | if (src_ty.isSignedInt()) .sar else .shr, | 3372 | if (src_ty.isSignedInt()) .sar else .shr, |
| 3463 | src_ty, | 3373 | src_ty, |
| 3464 | dst_mcv, | 3374 | dst_mcv, |
| 3465 | .{ .immediate = extra }, | 3375 | .{ .immediate = extra }, |
| 3466 | ), | 3376 | ), |
| 3467 | } | 3377 | } |
| 3468 | break :result dst_mcv; | | |
| 3469 | }; | | |
| 3470 | | 3378 | |
| 3471 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3379 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3472 | } | 3380 | } |
| 3473 | | 3381 | |
| 3474 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | 3382 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 3475 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3383 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3476 | const result = result: { | | |
| 3477 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 3478 | | 3384 | |
| 3479 | const src_ty = self.air.typeOf(ty_op.operand); | 3385 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3480 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 3386 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 3481 | const src_mcv = try self.resolveInst(ty_op.operand); | 3387 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3482 | | 3388 | |
| 3483 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); | 3389 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); |
| 3484 | const dst_reg = dst_mcv.register; | 3390 | const dst_reg = dst_mcv.register; |
| 3485 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 3391 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3486 | defer self.register_manager.unlockReg(dst_lock); | 3392 | defer self.register_manager.unlockReg(dst_lock); |
| 3487 | | 3393 | |
| 3488 | const tmp_reg = try self.register_manager.allocReg(null, gp); | 3394 | const tmp_reg = try self.register_manager.allocReg(null, gp); |
| 3489 | const tmp_lock = self.register_manager.lockReg(tmp_reg); | 3395 | const tmp_lock = self.register_manager.lockReg(tmp_reg); |
| 3490 | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); | 3396 | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); |
| 3491 | | 3397 | |
| 3492 | { | 3398 | { |
| 3493 | const dst = registerAlias(dst_reg, src_abi_size); | 3399 | const dst = registerAlias(dst_reg, src_abi_size); |
| 3494 | const tmp = registerAlias(tmp_reg, src_abi_size); | 3400 | const tmp = registerAlias(tmp_reg, src_abi_size); |
| 3495 | const imm = if (src_abi_size > 4) | 3401 | const imm = if (src_abi_size > 4) |
| 3496 | try self.register_manager.allocReg(null, gp) | 3402 | try self.register_manager.allocReg(null, gp) |
| 3497 | else | 3403 | else |
| 3498 | undefined; | 3404 | undefined; |
| 3499 | | 3405 | |
| 3500 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8); | 3406 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8); |
| 3501 | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); | 3407 | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); |
| 3502 | const imm_00_11 = Immediate.u(mask / 0b01_01); | 3408 | const imm_00_11 = Immediate.u(mask / 0b01_01); |
| 3503 | const imm_0_1 = Immediate.u(mask / 0b1_1); | 3409 | const imm_0_1 = Immediate.u(mask / 0b1_1); |
| 3504 | | 3410 | |
| 3505 | // dst = temp1 = bswap(operand) | 3411 | // dst = temp1 = bswap(operand) |
| 3506 | try self.asmRegisterRegister(.mov, tmp, dst); | 3412 | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3507 | // tmp = temp1 | 3413 | // tmp = temp1 |
| 3508 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(4)); | 3414 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(4)); |
| 3509 | // dst = temp1 >> 4 | 3415 | // dst = temp1 >> 4 |
| 3510 | if (src_abi_size > 4) { | 3416 | if (src_abi_size > 4) { |
| 3511 | try self.asmRegisterImmediate(.mov, imm, imm_0000_1111); | 3417 | try self.asmRegisterImmediate(.mov, imm, imm_0000_1111); |
| 3512 | try self.asmRegisterRegister(.@"and", tmp, imm); | 3418 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3513 | try self.asmRegisterRegister(.@"and", dst, imm); | 3419 | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3514 | } else { | 3420 | } else { |
| 3515 | try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111); | 3421 | try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111); |
| 3516 | try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111); | 3422 | try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111); |
| 3517 | } | 3423 | } |
| 3518 | // tmp = temp1 & 0x0F...0F | 3424 | // tmp = temp1 & 0x0F...0F |
| 3519 | // dst = (temp1 >> 4) & 0x0F...0F | 3425 | // dst = (temp1 >> 4) & 0x0F...0F |
| 3520 | try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4)); | 3426 | try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4)); |
| 3521 | // tmp = (temp1 & 0x0F...0F) << 4 | 3427 | // tmp = (temp1 & 0x0F...0F) << 4 |
| 3522 | try self.asmRegisterRegister(.@"or", dst, tmp); | 3428 | try self.asmRegisterRegister(.@"or", dst, tmp); |
| 3523 | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) | 3429 | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) |
| 3524 | try self.asmRegisterRegister(.mov, tmp, dst); | 3430 | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3525 | // tmp = temp2 | 3431 | // tmp = temp2 |
| 3526 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(2)); | 3432 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(2)); |
| 3527 | // dst = temp2 >> 2 | 3433 | // dst = temp2 >> 2 |
| 3528 | if (src_abi_size > 4) { | 3434 | if (src_abi_size > 4) { |
| 3529 | try self.asmRegisterImmediate(.mov, imm, imm_00_11); | 3435 | try self.asmRegisterImmediate(.mov, imm, imm_00_11); |
| 3530 | try self.asmRegisterRegister(.@"and", tmp, imm); | 3436 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3531 | try self.asmRegisterRegister(.@"and", dst, imm); | 3437 | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3532 | } else { | 3438 | } else { |
| 3533 | try self.asmRegisterImmediate(.@"and", tmp, imm_00_11); | 3439 | try self.asmRegisterImmediate(.@"and", tmp, imm_00_11); |
| 3534 | try self.asmRegisterImmediate(.@"and", dst, imm_00_11); | 3440 | try self.asmRegisterImmediate(.@"and", dst, imm_00_11); |
| 3535 | } | | |
| 3536 | // tmp = temp2 & 0x33...33 | | |
| 3537 | // dst = (temp2 >> 2) & 0x33...33 | | |
| 3538 | try self.asmRegisterMemory( | | |
| 3539 | .lea, | | |
| 3540 | if (src_abi_size > 4) tmp.to64() else tmp.to32(), | | |
| 3541 | Memory.sib(.qword, .{ | | |
| 3542 | .base = dst.to64(), | | |
| 3543 | .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 }, | | |
| 3544 | }), | | |
| 3545 | ); | | |
| 3546 | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) | | |
| 3547 | try self.asmRegisterRegister(.mov, dst, tmp); | | |
| 3548 | // dst = temp3 | | |
| 3549 | try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1)); | | |
| 3550 | // tmp = temp3 >> 1 | | |
| 3551 | if (src_abi_size > 4) { | | |
| 3552 | try self.asmRegisterImmediate(.mov, imm, imm_0_1); | | |
| 3553 | try self.asmRegisterRegister(.@"and", dst, imm); | | |
| 3554 | try self.asmRegisterRegister(.@"and", tmp, imm); | | |
| 3555 | } else { | | |
| 3556 | try self.asmRegisterImmediate(.@"and", dst, imm_0_1); | | |
| 3557 | try self.asmRegisterImmediate(.@"and", tmp, imm_0_1); | | |
| 3558 | } | | |
| 3559 | // dst = temp3 & 0x55...55 | | |
| 3560 | // tmp = (temp3 >> 1) & 0x55...55 | | |
| 3561 | try self.asmRegisterMemory( | | |
| 3562 | .lea, | | |
| 3563 | if (src_abi_size > 4) dst.to64() else dst.to32(), | | |
| 3564 | Memory.sib(.qword, .{ | | |
| 3565 | .base = tmp.to64(), | | |
| 3566 | .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 }, | | |
| 3567 | }), | | |
| 3568 | ); | | |
| 3569 | // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1) | | |
| 3570 | } | 3441 | } |
| | 3442 | // tmp = temp2 & 0x33...33 |
| | 3443 | // dst = (temp2 >> 2) & 0x33...33 |
| | 3444 | try self.asmRegisterMemory( |
| | 3445 | .lea, |
| | 3446 | if (src_abi_size > 4) tmp.to64() else tmp.to32(), |
| | 3447 | Memory.sib(.qword, .{ |
| | 3448 | .base = dst.to64(), |
| | 3449 | .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 }, |
| | 3450 | }), |
| | 3451 | ); |
| | 3452 | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) |
| | 3453 | try self.asmRegisterRegister(.mov, dst, tmp); |
| | 3454 | // dst = temp3 |
| | 3455 | try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1)); |
| | 3456 | // tmp = temp3 >> 1 |
| | 3457 | if (src_abi_size > 4) { |
| | 3458 | try self.asmRegisterImmediate(.mov, imm, imm_0_1); |
| | 3459 | try self.asmRegisterRegister(.@"and", dst, imm); |
| | 3460 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| | 3461 | } else { |
| | 3462 | try self.asmRegisterImmediate(.@"and", dst, imm_0_1); |
| | 3463 | try self.asmRegisterImmediate(.@"and", tmp, imm_0_1); |
| | 3464 | } |
| | 3465 | // dst = temp3 & 0x55...55 |
| | 3466 | // tmp = (temp3 >> 1) & 0x55...55 |
| | 3467 | try self.asmRegisterMemory( |
| | 3468 | .lea, |
| | 3469 | if (src_abi_size > 4) dst.to64() else dst.to32(), |
| | 3470 | Memory.sib(.qword, .{ |
| | 3471 | .base = tmp.to64(), |
| | 3472 | .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 }, |
| | 3473 | }), |
| | 3474 | ); |
| | 3475 | // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1) |
| | 3476 | } |
| 3571 | | 3477 | |
| 3572 | switch (self.regExtraBits(src_ty)) { | 3478 | switch (self.regExtraBits(src_ty)) { |
| 3573 | 0 => {}, | 3479 | 0 => {}, |
| 3574 | else => |extra| try self.genBinOpMir( | 3480 | else => |extra| try self.genBinOpMir( |
| 3575 | if (src_ty.isSignedInt()) .sar else .shr, | 3481 | if (src_ty.isSignedInt()) .sar else .shr, |
| 3576 | src_ty, | 3482 | src_ty, |
| 3577 | dst_mcv, | 3483 | dst_mcv, |
| 3578 | .{ .immediate = extra }, | 3484 | .{ .immediate = extra }, |
| 3579 | ), | 3485 | ), |
| 3580 | } | 3486 | } |
| 3581 | break :result dst_mcv; | | |
| 3582 | }; | | |
| 3583 | | 3487 | |
| 3584 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3488 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3585 | } | 3489 | } |
| 3586 | | 3490 | |
| 3587 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | 3491 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| 3588 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 3492 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3589 | const result: MCValue = if (self.liveness.isUnused(inst)) | 3493 | _ = un_op; |
| 3590 | .unreach | 3494 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); |
| 3591 | else | 3495 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3592 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | | |
| 3593 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | | |
| 3594 | } | 3496 | } |
| 3595 | | 3497 | |
| 3596 | fn reuseOperand( | 3498 | fn reuseOperand( |
| ... | @@ -3763,9 +3665,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3763,9 +3665,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3763 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); | 3665 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 3764 | | 3666 | |
| 3765 | const ptr = try self.resolveInst(ty_op.operand); | 3667 | const ptr = try self.resolveInst(ty_op.operand); |
| 3766 | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); | | |
| 3767 | if (self.liveness.isUnused(inst) and !is_volatile) break :result .unreach; | | |
| 3768 | | | |
| 3769 | const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) | 3668 | const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) |
| 3770 | // The MCValue that holds the pointer can be re-used as the value. | 3669 | // The MCValue that holds the pointer can be re-used as the value. |
| 3771 | ptr | 3670 | ptr |
| ... | @@ -4062,10 +3961,6 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | ... | @@ -4062,10 +3961,6 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 4062 | } | 3961 | } |
| 4063 | | 3962 | |
| 4064 | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { | 3963 | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4065 | if (self.liveness.isUnused(inst)) { | | |
| 4066 | return MCValue.unreach; | | |
| 4067 | } | | |
| 4068 | | | |
| 4069 | const mcv = try self.resolveInst(operand); | 3964 | const mcv = try self.resolveInst(operand); |
| 4070 | const ptr_ty = self.air.typeOf(operand); | 3965 | const ptr_ty = self.air.typeOf(operand); |
| 4071 | const container_ty = ptr_ty.childType(); | 3966 | const container_ty = ptr_ty.childType(); |
| ... | @@ -4132,7 +4027,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 | ... | @@ -4132,7 +4027,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 4132 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 4027 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4133 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 4028 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4134 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 4029 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 4135 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 4030 | const result: MCValue = result: { |
| 4136 | const operand = extra.struct_operand; | 4031 | const operand = extra.struct_operand; |
| 4137 | const index = extra.field_index; | 4032 | const index = extra.field_index; |
| 4138 | | 4033 | |
| ... | @@ -4280,11 +4175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4280,11 +4175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4280 | | 4175 | |
| 4281 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 4176 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4282 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4177 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4283 | const result: MCValue = if (self.liveness.isUnused(inst)) | 4178 | _ = ty_op; |
| 4284 | .unreach | 4179 | return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch}); |
| 4285 | else | 4180 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 4286 | return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch}); | | |
| 4287 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 4288 | } | 4181 | } |
| 4289 | | 4182 | |
| 4290 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { | 4183 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| ... | @@ -5503,9 +5396,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5503,9 +5396,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 5503 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 5396 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 5504 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); | 5397 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| 5505 | | 5398 | |
| 5506 | const result: MCValue = result: { | 5399 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5507 | if (self.liveness.isUnused(inst)) break :result .unreach; | | |
| 5508 | | | |
| 5509 | const dst_mcv: MCValue = switch (mcv) { | 5400 | const dst_mcv: MCValue = switch (mcv) { |
| 5510 | .register => |reg| blk: { | 5401 | .register => |reg| blk: { |
| 5511 | self.register_manager.getRegAssumeFree(reg.to64(), inst); | 5402 | self.register_manager.getRegAssumeFree(reg.to64(), inst); |
| ... | @@ -5596,23 +5487,17 @@ fn airBreakpoint(self: *Self) !void { | ... | @@ -5596,23 +5487,17 @@ fn airBreakpoint(self: *Self) !void { |
| 5596 | } | 5487 | } |
| 5597 | | 5488 | |
| 5598 | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { | 5489 | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { |
| 5599 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 5490 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5600 | const dst_mcv = try self.allocRegOrMem(inst, true); | 5491 | try self.setRegOrMem(Type.usize, dst_mcv, .{ |
| 5601 | try self.setRegOrMem(Type.usize, dst_mcv, .{ | 5492 | .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)), |
| 5602 | .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)), | 5493 | }); |
| 5603 | }); | 5494 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 5604 | break :result dst_mcv; | | |
| 5605 | }; | | |
| 5606 | return self.finishAir(inst, result, .{ .none, .none, .none }); | | |
| 5607 | } | 5495 | } |
| 5608 | | 5496 | |
| 5609 | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { | 5497 | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { |
| 5610 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 5498 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5611 | const dst_mcv = try self.allocRegOrMem(inst, true); | 5499 | try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp }); |
| 5612 | try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp }); | 5500 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 5613 | break :result dst_mcv; | | |
| 5614 | }; | | |
| 5615 | return self.finishAir(inst, result, .{ .none, .none, .none }); | | |
| 5616 | } | 5501 | } |
| 5617 | | 5502 | |
| 5618 | fn airFence(self: *Self, inst: Air.Inst.Index) !void { | 5503 | fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -5892,60 +5777,58 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5892,60 +5777,58 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5892 | | 5777 | |
| 5893 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 5778 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 5894 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5779 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5895 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 5780 | const ty = self.air.typeOf(bin_op.lhs); |
| 5896 | const ty = self.air.typeOf(bin_op.lhs); | 5781 | const ty_abi_size = ty.abiSize(self.target.*); |
| 5897 | const ty_abi_size = ty.abiSize(self.target.*); | 5782 | const can_reuse = ty_abi_size <= 8; |
| 5898 | const can_reuse = ty_abi_size <= 8; | | |
| 5899 | | 5783 | |
| 5900 | try self.spillEflagsIfOccupied(); | 5784 | try self.spillEflagsIfOccupied(); |
| 5901 | self.eflags_inst = inst; | 5785 | self.eflags_inst = inst; |
| 5902 | | 5786 | |
| 5903 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 5787 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 5904 | const lhs_lock = switch (lhs_mcv) { | 5788 | const lhs_lock = switch (lhs_mcv) { |
| 5905 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 5789 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5906 | else => null, | 5790 | else => null, |
| 5907 | }; | 5791 | }; |
| 5908 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 5792 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5909 | | 5793 | |
| 5910 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 5794 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5911 | const rhs_lock = switch (rhs_mcv) { | 5795 | const rhs_lock = switch (rhs_mcv) { |
| 5912 | .register => |reg| self.register_manager.lockReg(reg), | 5796 | .register => |reg| self.register_manager.lockReg(reg), |
| 5913 | else => null, | 5797 | else => null, |
| 5914 | }; | 5798 | }; |
| 5915 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 5799 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5916 | | 5800 | |
| 5917 | const dst_mem_ok = !ty.isRuntimeFloat(); | 5801 | const dst_mem_ok = !ty.isRuntimeFloat(); |
| 5918 | var flipped = false; | 5802 | var flipped = false; |
| 5919 | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and | 5803 | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and |
| 5920 | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) | 5804 | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) |
| 5921 | lhs_mcv | 5805 | lhs_mcv |
| 5922 | else if (can_reuse and !rhs_mcv.isImmediate() and | 5806 | else if (can_reuse and !rhs_mcv.isImmediate() and |
| 5923 | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) | 5807 | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) |
| 5924 | dst: { | 5808 | dst: { |
| 5925 | flipped = true; | 5809 | flipped = true; |
| 5926 | break :dst rhs_mcv; | 5810 | break :dst rhs_mcv; |
| 5927 | } else if (dst_mem_ok) dst: { | 5811 | } else if (dst_mem_ok) dst: { |
| 5928 | const dst_mcv = try self.allocTempRegOrMem(ty, true); | 5812 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| 5929 | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); | 5813 | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); |
| 5930 | break :dst dst_mcv; | 5814 | break :dst dst_mcv; |
| 5931 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; | 5815 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| 5932 | const dst_lock = switch (dst_mcv) { | 5816 | const dst_lock = switch (dst_mcv) { |
| 5933 | .register => |reg| self.register_manager.lockReg(reg), | 5817 | .register => |reg| self.register_manager.lockReg(reg), |
| 5934 | else => null, | 5818 | else => null, |
| 5935 | }; | 5819 | }; |
| 5936 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 5820 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5937 | | 5821 | |
| 5938 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; | 5822 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 5939 | try self.genBinOpMir(switch (ty.tag()) { | 5823 | try self.genBinOpMir(switch (ty.tag()) { |
| 5940 | else => .cmp, | 5824 | else => .cmp, |
| 5941 | .f32 => .ucomiss, | 5825 | .f32 => .ucomiss, |
| 5942 | .f64 => .ucomisd, | 5826 | .f64 => .ucomisd, |
| 5943 | }, ty, dst_mcv, src_mcv); | 5827 | }, ty, dst_mcv, src_mcv); |
| 5944 | | 5828 | |
| 5945 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; | 5829 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| 5946 | break :result .{ | 5830 | const result = MCValue{ |
| 5947 | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), | 5831 | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), |
| 5948 | }; | | |
| 5949 | }; | 5832 | }; |
| 5950 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 5833 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5951 | } | 5834 | } |
| ... | @@ -5957,56 +5840,55 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5957,56 +5840,55 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| 5957 | | 5840 | |
| 5958 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { | 5841 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 5959 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5842 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5960 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | | |
| 5961 | const addr_reg = try self.register_manager.allocReg(null, gp); | | |
| 5962 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | | |
| 5963 | defer self.register_manager.unlockReg(addr_lock); | | |
| 5964 | | | |
| 5965 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | | |
| 5966 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( | | |
| 5967 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 5968 | 4, // dword alignment | | |
| 5969 | ); | | |
| 5970 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); | | |
| 5971 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ | | |
| 5972 | .base = .ds, | | |
| 5973 | .disp = @intCast(i32, got_addr), | | |
| 5974 | })); | | |
| 5975 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | | |
| 5976 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( | | |
| 5977 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 5978 | 4, // dword alignment | | |
| 5979 | ); | | |
| 5980 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | | |
| 5981 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); | | |
| 5982 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | | |
| 5983 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( | | |
| 5984 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 5985 | 4, // dword alignment | | |
| 5986 | ); | | |
| 5987 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | | |
| 5988 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); | | |
| 5989 | } else { | | |
| 5990 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); | | |
| 5991 | } | | |
| 5992 | | 5843 | |
| 5993 | try self.spillEflagsIfOccupied(); | 5844 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 5994 | self.eflags_inst = inst; | 5845 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| | 5846 | defer self.register_manager.unlockReg(addr_lock); |
| 5995 | | 5847 | |
| 5996 | const op_ty = self.air.typeOf(un_op); | 5848 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 5997 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); | 5849 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 5998 | const op_mcv = try self.resolveInst(un_op); | 5850 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5999 | const dst_reg = switch (op_mcv) { | 5851 | 4, // dword alignment |
| 6000 | .register => |reg| reg, | 5852 | ); |
| 6001 | else => try self.copyToTmpRegister(op_ty, op_mcv), | 5853 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 6002 | }; | 5854 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 6003 | try self.asmRegisterMemory( | 5855 | .base = .ds, |
| 6004 | .cmp, | 5856 | .disp = @intCast(i32, got_addr), |
| 6005 | registerAlias(dst_reg, op_abi_size), | 5857 | })); |
| 6006 | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }), | 5858 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| | 5859 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| | 5860 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 5861 | 4, // dword alignment |
| 6007 | ); | 5862 | ); |
| 6008 | break :result .{ .eflags = .b }; | 5863 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| | 5864 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| | 5865 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| | 5866 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| | 5867 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 5868 | 4, // dword alignment |
| | 5869 | ); |
| | 5870 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| | 5871 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| | 5872 | } else { |
| | 5873 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| | 5874 | } |
| | 5875 | |
| | 5876 | try self.spillEflagsIfOccupied(); |
| | 5877 | self.eflags_inst = inst; |
| | 5878 | |
| | 5879 | const op_ty = self.air.typeOf(un_op); |
| | 5880 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); |
| | 5881 | const op_mcv = try self.resolveInst(un_op); |
| | 5882 | const dst_reg = switch (op_mcv) { |
| | 5883 | .register => |reg| reg, |
| | 5884 | else => try self.copyToTmpRegister(op_ty, op_mcv), |
| 6009 | }; | 5885 | }; |
| | 5886 | try self.asmRegisterMemory( |
| | 5887 | .cmp, |
| | 5888 | registerAlias(dst_reg, op_abi_size), |
| | 5889 | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }), |
| | 5890 | ); |
| | 5891 | const result = MCValue{ .eflags = .b }; |
| 6010 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 5892 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6011 | } | 5893 | } |
| 6012 | | 5894 | |
| ... | @@ -6365,67 +6247,53 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa | ... | @@ -6365,67 +6247,53 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa |
| 6365 | | 6247 | |
| 6366 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | 6248 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 6367 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6249 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6368 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6250 | const operand = try self.resolveInst(un_op); |
| 6369 | const operand = try self.resolveInst(un_op); | 6251 | const ty = self.air.typeOf(un_op); |
| 6370 | const ty = self.air.typeOf(un_op); | 6252 | const result = try self.isNull(inst, ty, operand); |
| 6371 | break :result try self.isNull(inst, ty, operand); | | |
| 6372 | }; | | |
| 6373 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6253 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6374 | } | 6254 | } |
| 6375 | | 6255 | |
| 6376 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 6256 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6377 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6257 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6378 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6258 | const operand = try self.resolveInst(un_op); |
| 6379 | const operand = try self.resolveInst(un_op); | 6259 | const ty = self.air.typeOf(un_op); |
| 6380 | const ty = self.air.typeOf(un_op); | 6260 | const result = try self.isNullPtr(inst, ty, operand); |
| 6381 | break :result try self.isNullPtr(inst, ty, operand); | | |
| 6382 | }; | | |
| 6383 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6261 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6384 | } | 6262 | } |
| 6385 | | 6263 | |
| 6386 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | 6264 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 6387 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6265 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6388 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6266 | const operand = try self.resolveInst(un_op); |
| 6389 | const operand = try self.resolveInst(un_op); | 6267 | const ty = self.air.typeOf(un_op); |
| 6390 | const ty = self.air.typeOf(un_op); | 6268 | const result = switch (try self.isNull(inst, ty, operand)) { |
| 6391 | break :result switch (try self.isNull(inst, ty, operand)) { | 6269 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6392 | .eflags => |cc| .{ .eflags = cc.negate() }, | 6270 | else => unreachable, |
| 6393 | else => unreachable, | | |
| 6394 | }; | | |
| 6395 | }; | 6271 | }; |
| 6396 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6272 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6397 | } | 6273 | } |
| 6398 | | 6274 | |
| 6399 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 6275 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6400 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6276 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6401 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6277 | const operand = try self.resolveInst(un_op); |
| 6402 | const operand = try self.resolveInst(un_op); | 6278 | const ty = self.air.typeOf(un_op); |
| 6403 | const ty = self.air.typeOf(un_op); | 6279 | const result = switch (try self.isNullPtr(inst, ty, operand)) { |
| 6404 | break :result switch (try self.isNullPtr(inst, ty, operand)) { | 6280 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6405 | .eflags => |cc| .{ .eflags = cc.negate() }, | 6281 | else => unreachable, |
| 6406 | else => unreachable, | | |
| 6407 | }; | | |
| 6408 | }; | 6282 | }; |
| 6409 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6283 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6410 | } | 6284 | } |
| 6411 | | 6285 | |
| 6412 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | 6286 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 6413 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6287 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6414 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6288 | const operand = try self.resolveInst(un_op); |
| 6415 | const operand = try self.resolveInst(un_op); | 6289 | const ty = self.air.typeOf(un_op); |
| 6416 | const ty = self.air.typeOf(un_op); | 6290 | const result = try self.isErr(inst, ty, operand); |
| 6417 | break :result try self.isErr(inst, ty, operand); | | |
| 6418 | }; | | |
| 6419 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6291 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6420 | } | 6292 | } |
| 6421 | | 6293 | |
| 6422 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 6294 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6423 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6295 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6424 | | 6296 | |
| 6425 | if (self.liveness.isUnused(inst)) { | | |
| 6426 | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); | | |
| 6427 | } | | |
| 6428 | | | |
| 6429 | const operand_ptr = try self.resolveInst(un_op); | 6297 | const operand_ptr = try self.resolveInst(un_op); |
| 6430 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 6298 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 6431 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6299 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -6451,21 +6319,15 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6451,21 +6319,15 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6451 | | 6319 | |
| 6452 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | 6320 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 6453 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6321 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6454 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 6322 | const operand = try self.resolveInst(un_op); |
| 6455 | const operand = try self.resolveInst(un_op); | 6323 | const ty = self.air.typeOf(un_op); |
| 6456 | const ty = self.air.typeOf(un_op); | 6324 | const result = try self.isNonErr(inst, ty, operand); |
| 6457 | break :result try self.isNonErr(inst, ty, operand); | | |
| 6458 | }; | | |
| 6459 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 6325 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6460 | } | 6326 | } |
| 6461 | | 6327 | |
| 6462 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 6328 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6463 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6329 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6464 | | 6330 | |
| 6465 | if (self.liveness.isUnused(inst)) { | | |
| 6466 | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); | | |
| 6467 | } | | |
| 6468 | | | |
| 6469 | const operand_ptr = try self.resolveInst(un_op); | 6331 | const operand_ptr = try self.resolveInst(un_op); |
| 6470 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 6332 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 6471 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6333 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -6691,7 +6553,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6691,7 +6553,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6691 | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | 6553 | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6692 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 6554 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6693 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); | 6555 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
| 6694 | const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; | | |
| 6695 | const clobbers_len = @truncate(u31, extra.data.flags); | 6556 | const clobbers_len = @truncate(u31, extra.data.flags); |
| 6696 | var extra_i: usize = extra.end; | 6557 | var extra_i: usize = extra.end; |
| 6697 | const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); | 6558 | const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); |
| ... | @@ -6700,216 +6561,214 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6700,216 +6561,214 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6700 | extra_i += inputs.len; | 6561 | extra_i += inputs.len; |
| 6701 | | 6562 | |
| 6702 | var result: MCValue = .none; | 6563 | var result: MCValue = .none; |
| 6703 | if (!is_volatile and self.liveness.isUnused(inst)) result = .unreach else { | 6564 | var args = std.StringArrayHashMap(MCValue).init(self.gpa); |
| 6704 | var args = std.StringArrayHashMap(MCValue).init(self.gpa); | 6565 | try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len); |
| 6705 | try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len); | 6566 | defer { |
| 6706 | defer { | 6567 | for (args.values()) |arg| switch (arg) { |
| 6707 | for (args.values()) |arg| switch (arg) { | 6568 | .register => |reg| self.register_manager.unlockReg(.{ .register = reg }), |
| 6708 | .register => |reg| self.register_manager.unlockReg(.{ .register = reg }), | 6569 | else => {}, |
| 6709 | else => {}, | 6570 | }; |
| 6710 | }; | 6571 | args.deinit(); |
| 6711 | args.deinit(); | 6572 | } |
| 6712 | } | 6573 | |
| | 6574 | if (outputs.len > 1) { |
| | 6575 | return self.fail("TODO implement codegen for asm with more than 1 output", .{}); |
| | 6576 | } |
| 6713 | | 6577 | |
| 6714 | if (outputs.len > 1) { | 6578 | for (outputs) |output| { |
| 6715 | return self.fail("TODO implement codegen for asm with more than 1 output", .{}); | 6579 | if (output != .none) { |
| | 6580 | return self.fail("TODO implement codegen for non-expr asm", .{}); |
| | 6581 | } |
| | 6582 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| | 6583 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| | 6584 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| | 6585 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| | 6586 | // for the string, we still use the next u32 for the null terminator. |
| | 6587 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| | 6588 | |
| | 6589 | const mcv: MCValue = if (mem.eql(u8, constraint, "=r")) |
| | 6590 | .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse |
| | 6591 | return self.fail("ran out of registers lowering inline asm", .{}) } |
| | 6592 | else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}")) |
| | 6593 | .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse |
| | 6594 | return self.fail("unrecognized register constraint: '{s}'", .{constraint}) } |
| | 6595 | else |
| | 6596 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); |
| | 6597 | args.putAssumeCapacity(name, mcv); |
| | 6598 | switch (mcv) { |
| | 6599 | .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_| |
| | 6600 | self.register_manager.lockRegAssumeUnused(reg), |
| | 6601 | else => {}, |
| 6716 | } | 6602 | } |
| | 6603 | if (output == .none) result = mcv; |
| | 6604 | } |
| 6717 | | 6605 | |
| 6718 | for (outputs) |output| { | 6606 | for (inputs) |input| { |
| 6719 | if (output != .none) { | 6607 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6720 | return self.fail("TODO implement codegen for non-expr asm", .{}); | 6608 | const constraint = std.mem.sliceTo(input_bytes, 0); |
| 6721 | } | 6609 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 6722 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | 6610 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6723 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); | 6611 | // for the string, we still use the next u32 for the null terminator. |
| 6724 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 6612 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6725 | // This equation accounts for the fact that even if we have exactly 4 bytes | 6613 | |
| 6726 | // for the string, we still use the next u32 for the null terminator. | 6614 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 6727 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 6615 | return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); |
| 6728 | | | |
| 6729 | const mcv: MCValue = if (mem.eql(u8, constraint, "=r")) | | |
| 6730 | .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse | | |
| 6731 | return self.fail("ran out of registers lowering inline asm", .{}) } | | |
| 6732 | else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}")) | | |
| 6733 | .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse | | |
| 6734 | return self.fail("unrecognized register constraint: '{s}'", .{constraint}) } | | |
| 6735 | else | | |
| 6736 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); | | |
| 6737 | args.putAssumeCapacity(name, mcv); | | |
| 6738 | switch (mcv) { | | |
| 6739 | .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_| | | |
| 6740 | self.register_manager.lockRegAssumeUnused(reg), | | |
| 6741 | else => {}, | | |
| 6742 | } | | |
| 6743 | if (output == .none) result = mcv; | | |
| 6744 | } | 6616 | } |
| | 6617 | const reg_name = constraint[1 .. constraint.len - 1]; |
| | 6618 | const reg = parseRegName(reg_name) orelse |
| | 6619 | return self.fail("unrecognized register: '{s}'", .{reg_name}); |
| 6745 | | 6620 | |
| 6746 | for (inputs) |input| { | 6621 | const arg_mcv = try self.resolveInst(input); |
| 6747 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | 6622 | try self.register_manager.getReg(reg, null); |
| 6748 | const constraint = std.mem.sliceTo(input_bytes, 0); | 6623 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); |
| 6749 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); | 6624 | } |
| | 6625 | |
| | 6626 | { |
| | 6627 | var clobber_i: u32 = 0; |
| | 6628 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| | 6629 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6750 | // This equation accounts for the fact that even if we have exactly 4 bytes | 6630 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6751 | // for the string, we still use the next u32 for the null terminator. | 6631 | // for the string, we still use the next u32 for the null terminator. |
| 6752 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 6632 | extra_i += clobber.len / 4 + 1; |
| 6753 | | 6633 | |
| 6754 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { | 6634 | // TODO honor these |
| 6755 | return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); | | |
| 6756 | } | | |
| 6757 | const reg_name = constraint[1 .. constraint.len - 1]; | | |
| 6758 | const reg = parseRegName(reg_name) orelse | | |
| 6759 | return self.fail("unrecognized register: '{s}'", .{reg_name}); | | |
| 6760 | | | |
| 6761 | const arg_mcv = try self.resolveInst(input); | | |
| 6762 | try self.register_manager.getReg(reg, null); | | |
| 6763 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); | | |
| 6764 | } | | |
| 6765 | | | |
| 6766 | { | | |
| 6767 | var clobber_i: u32 = 0; | | |
| 6768 | while (clobber_i < clobbers_len) : (clobber_i += 1) { | | |
| 6769 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); | | |
| 6770 | // This equation accounts for the fact that even if we have exactly 4 bytes | | |
| 6771 | // for the string, we still use the next u32 for the null terminator. | | |
| 6772 | extra_i += clobber.len / 4 + 1; | | |
| 6773 | | | |
| 6774 | // TODO honor these | | |
| 6775 | } | | |
| 6776 | } | 6635 | } |
| | 6636 | } |
| 6777 | | 6637 | |
| 6778 | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; | 6638 | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 6779 | var line_it = mem.tokenize(u8, asm_source, "\n\r;"); | 6639 | var line_it = mem.tokenize(u8, asm_source, "\n\r;"); |
| 6780 | while (line_it.next()) |line| { | 6640 | while (line_it.next()) |line| { |
| 6781 | var mnem_it = mem.tokenize(u8, line, " \t"); | 6641 | var mnem_it = mem.tokenize(u8, line, " \t"); |
| 6782 | const mnem_str = mnem_it.next() orelse continue; | 6642 | const mnem_str = mnem_it.next() orelse continue; |
| 6783 | if (mem.startsWith(u8, mnem_str, "#")) continue; | 6643 | if (mem.startsWith(u8, mnem_str, "#")) continue; |
| 6784 | | 6644 | |
| 6785 | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) | 6645 | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) |
| 6786 | .byte | 6646 | .byte |
| 6787 | else if (mem.endsWith(u8, mnem_str, "w")) | 6647 | else if (mem.endsWith(u8, mnem_str, "w")) |
| 6788 | .word | 6648 | .word |
| 6789 | else if (mem.endsWith(u8, mnem_str, "l")) | 6649 | else if (mem.endsWith(u8, mnem_str, "l")) |
| 6790 | .dword | 6650 | .dword |
| 6791 | else if (mem.endsWith(u8, mnem_str, "q")) | 6651 | else if (mem.endsWith(u8, mnem_str, "q")) |
| 6792 | .qword | 6652 | .qword |
| 6793 | else | 6653 | else |
| 6794 | null; | 6654 | null; |
| 6795 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse | 6655 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse |
| 6796 | (if (mnem_size) |_| | 6656 | (if (mnem_size) |_| |
| 6797 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) | 6657 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) |
| 6798 | else | 6658 | else |
| 6799 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); | 6659 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); |
| 6800 | | 6660 | |
| 6801 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); | 6661 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6802 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; | 6662 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; |
| 6803 | for (&ops) |*op| { | 6663 | for (&ops) |*op| { |
| 6804 | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); | 6664 | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); |
| 6805 | if (mem.startsWith(u8, op_str, "#")) break; | 6665 | if (mem.startsWith(u8, op_str, "#")) break; |
| 6806 | if (mem.startsWith(u8, op_str, "%%")) { | 6666 | if (mem.startsWith(u8, op_str, "%%")) { |
| 6807 | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); | 6667 | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 6808 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse | 6668 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse |
| 6809 | return self.fail("Invalid register: '{s}'", .{op_str}); | 6669 | return self.fail("Invalid register: '{s}'", .{op_str}); |
| 6810 | if (colon) |colon_pos| { | 6670 | if (colon) |colon_pos| { |
| 6811 | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch | 6671 | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch |
| 6812 | return self.fail("Invalid displacement: '{s}'", .{op_str}); | 6672 | return self.fail("Invalid displacement: '{s}'", .{op_str}); |
| 6813 | op.* = .{ .mem = Memory.sib( | 6673 | op.* = .{ .mem = Memory.sib( |
| 6814 | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), | 6674 | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), |
| 6815 | .{ .base = reg, .disp = disp }, | 6675 | .{ .base = reg, .disp = disp }, |
| 6816 | ) }; | 6676 | ) }; |
| 6817 | } else { | 6677 | } else { |
| 6818 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) | 6678 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) |
| 6819 | return self.fail("Invalid register size: '{s}'", .{op_str}); | 6679 | return self.fail("Invalid register size: '{s}'", .{op_str}); |
| 6820 | op.* = .{ .reg = reg }; | 6680 | op.* = .{ .reg = reg }; |
| | 6681 | } |
| | 6682 | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { |
| | 6683 | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse |
| | 6684 | return self.fail("No matching constraint: '{s}'", .{op_str})) { |
| | 6685 | .register => |reg| op.* = .{ .reg = reg }, |
| | 6686 | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), |
| | 6687 | } |
| | 6688 | } else if (mem.startsWith(u8, op_str, "$")) { |
| | 6689 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { |
| | 6690 | if (mnem_size) |size| { |
| | 6691 | const max = @as(u64, math.maxInt(u64)) >> |
| | 6692 | @intCast(u6, 64 - (size.bitSize() - 1)); |
| | 6693 | if ((if (s < 0) ~s else s) > max) |
| | 6694 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6821 | } | 6695 | } |
| 6822 | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { | 6696 | op.* = .{ .imm = Immediate.s(s) }; |
| 6823 | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse | 6697 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { |
| 6824 | return self.fail("No matching constraint: '{s}'", .{op_str})) { | 6698 | if (mnem_size) |size| { |
| 6825 | .register => |reg| op.* = .{ .reg = reg }, | 6699 | const max = @as(u64, math.maxInt(u64)) >> |
| 6826 | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), | 6700 | @intCast(u6, 64 - size.bitSize()); |
| | 6701 | if (u > max) |
| | 6702 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6827 | } | 6703 | } |
| 6828 | } else if (mem.startsWith(u8, op_str, "$")) { | 6704 | op.* = .{ .imm = Immediate.u(u) }; |
| 6829 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { | 6705 | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); |
| 6830 | if (mnem_size) |size| { | 6706 | } else return self.fail("Invalid operand: '{s}'", .{op_str}); |
| 6831 | const max = @as(u64, math.maxInt(u64)) >> | 6707 | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); |
| 6832 | @intCast(u6, 64 - (size.bitSize() - 1)); | 6708 | |
| 6833 | if ((if (s < 0) ~s else s) > max) | 6709 | (switch (ops[0]) { |
| 6834 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); | 6710 | .none => self.asmOpOnly(mnem), |
| 6835 | } | 6711 | .reg => |reg0| switch (ops[1]) { |
| 6836 | op.* = .{ .imm = Immediate.s(s) }; | 6712 | .none => self.asmRegister(mnem, reg0), |
| 6837 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { | 6713 | .reg => |reg1| switch (ops[2]) { |
| 6838 | if (mnem_size) |size| { | 6714 | .none => self.asmRegisterRegister(mnem, reg1, reg0), |
| 6839 | const max = @as(u64, math.maxInt(u64)) >> | 6715 | .reg => |reg2| switch (ops[3]) { |
| 6840 | @intCast(u6, 64 - size.bitSize()); | 6716 | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), |
| 6841 | if (u > max) | | |
| 6842 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); | | |
| 6843 | } | | |
| 6844 | op.* = .{ .imm = Immediate.u(u) }; | | |
| 6845 | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); | | |
| 6846 | } else return self.fail("Invalid operand: '{s}'", .{op_str}); | | |
| 6847 | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); | | |
| 6848 | | | |
| 6849 | (switch (ops[0]) { | | |
| 6850 | .none => self.asmOpOnly(mnem), | | |
| 6851 | .reg => |reg0| switch (ops[1]) { | | |
| 6852 | .none => self.asmRegister(mnem, reg0), | | |
| 6853 | .reg => |reg1| switch (ops[2]) { | | |
| 6854 | .none => self.asmRegisterRegister(mnem, reg1, reg0), | | |
| 6855 | .reg => |reg2| switch (ops[3]) { | | |
| 6856 | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), | | |
| 6857 | else => error.InvalidInstruction, | | |
| 6858 | }, | | |
| 6859 | .mem => |mem2| switch (ops[3]) { | | |
| 6860 | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), | | |
| 6861 | else => error.InvalidInstruction, | | |
| 6862 | }, | | |
| 6863 | else => error.InvalidInstruction, | 6717 | else => error.InvalidInstruction, |
| 6864 | }, | 6718 | }, |
| 6865 | .mem => |mem1| switch (ops[2]) { | 6719 | .mem => |mem2| switch (ops[3]) { |
| 6866 | .none => self.asmMemoryRegister(mnem, mem1, reg0), | 6720 | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), |
| 6867 | else => error.InvalidInstruction, | 6721 | else => error.InvalidInstruction, |
| 6868 | }, | 6722 | }, |
| 6869 | else => error.InvalidInstruction, | 6723 | else => error.InvalidInstruction, |
| 6870 | }, | 6724 | }, |
| 6871 | .mem => |mem0| switch (ops[1]) { | 6725 | .mem => |mem1| switch (ops[2]) { |
| 6872 | .none => self.asmMemory(mnem, mem0), | 6726 | .none => self.asmMemoryRegister(mnem, mem1, reg0), |
| 6873 | .reg => |reg1| switch (ops[2]) { | | |
| 6874 | .none => self.asmRegisterMemory(mnem, reg1, mem0), | | |
| 6875 | else => error.InvalidInstruction, | | |
| 6876 | }, | | |
| 6877 | else => error.InvalidInstruction, | 6727 | else => error.InvalidInstruction, |
| 6878 | }, | 6728 | }, |
| 6879 | .imm => |imm0| switch (ops[1]) { | 6729 | else => error.InvalidInstruction, |
| 6880 | .none => self.asmImmediate(mnem, imm0), | 6730 | }, |
| 6881 | .reg => |reg1| switch (ops[2]) { | 6731 | .mem => |mem0| switch (ops[1]) { |
| 6882 | .none => self.asmRegisterImmediate(mnem, reg1, imm0), | 6732 | .none => self.asmMemory(mnem, mem0), |
| 6883 | .reg => |reg2| switch (ops[3]) { | 6733 | .reg => |reg1| switch (ops[2]) { |
| 6884 | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), | 6734 | .none => self.asmRegisterMemory(mnem, reg1, mem0), |
| 6885 | else => error.InvalidInstruction, | 6735 | else => error.InvalidInstruction, |
| 6886 | }, | 6736 | }, |
| 6887 | .mem => |mem2| switch (ops[3]) { | 6737 | else => error.InvalidInstruction, |
| 6888 | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), | 6738 | }, |
| 6889 | else => error.InvalidInstruction, | 6739 | .imm => |imm0| switch (ops[1]) { |
| 6890 | }, | 6740 | .none => self.asmImmediate(mnem, imm0), |
| | 6741 | .reg => |reg1| switch (ops[2]) { |
| | 6742 | .none => self.asmRegisterImmediate(mnem, reg1, imm0), |
| | 6743 | .reg => |reg2| switch (ops[3]) { |
| | 6744 | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), |
| 6891 | else => error.InvalidInstruction, | 6745 | else => error.InvalidInstruction, |
| 6892 | }, | 6746 | }, |
| 6893 | .mem => |mem1| switch (ops[2]) { | 6747 | .mem => |mem2| switch (ops[3]) { |
| 6894 | .none => self.asmMemoryImmediate(mnem, mem1, imm0), | 6748 | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), |
| 6895 | else => error.InvalidInstruction, | 6749 | else => error.InvalidInstruction, |
| 6896 | }, | 6750 | }, |
| 6897 | else => error.InvalidInstruction, | 6751 | else => error.InvalidInstruction, |
| 6898 | }, | 6752 | }, |
| 6899 | }) catch |err| switch (err) { | 6753 | .mem => |mem1| switch (ops[2]) { |
| 6900 | error.InvalidInstruction => return self.fail( | 6754 | .none => self.asmMemoryImmediate(mnem, mem1, imm0), |
| 6901 | "Invalid instruction: '{s} {s} {s} {s} {s}'", | 6755 | else => error.InvalidInstruction, |
| 6902 | .{ | 6756 | }, |
| 6903 | @tagName(mnem), | 6757 | else => error.InvalidInstruction, |
| 6904 | @tagName(ops[0]), | 6758 | }, |
| 6905 | @tagName(ops[1]), | 6759 | }) catch |err| switch (err) { |
| 6906 | @tagName(ops[2]), | 6760 | error.InvalidInstruction => return self.fail( |
| 6907 | @tagName(ops[3]), | 6761 | "Invalid instruction: '{s} {s} {s} {s} {s}'", |
| 6908 | }, | 6762 | .{ |
| 6909 | ), | 6763 | @tagName(mnem), |
| 6910 | else => |e| return e, | 6764 | @tagName(ops[0]), |
| 6911 | }; | 6765 | @tagName(ops[1]), |
| 6912 | } | 6766 | @tagName(ops[2]), |
| | 6767 | @tagName(ops[3]), |
| | 6768 | }, |
| | 6769 | ), |
| | 6770 | else => |e| return e, |
| | 6771 | }; |
| 6913 | } | 6772 | } |
| 6914 | | 6773 | |
| 6915 | simple: { | 6774 | simple: { |
| ... | @@ -7811,7 +7670,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -7811,7 +7670,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7811 | | 7670 | |
| 7812 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | 7671 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7813 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 7672 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7814 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 7673 | const result = result: { |
| 7815 | const src_mcv = try self.resolveInst(un_op); | 7674 | const src_mcv = try self.resolveInst(un_op); |
| 7816 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; | 7675 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; |
| 7817 | | 7676 | |
| ... | @@ -7825,7 +7684,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7825,7 +7684,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7825 | | 7684 | |
| 7826 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | 7685 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7827 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7686 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7828 | const result = if (self.liveness.isUnused(inst)) .unreach else result: { | 7687 | const result = result: { |
| 7829 | const operand = try self.resolveInst(ty_op.operand); | 7688 | const operand = try self.resolveInst(ty_op.operand); |
| 7830 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | 7689 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; |
| 7831 | | 7690 | |
| ... | @@ -7850,28 +7709,24 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7850,28 +7709,24 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7850 | const ptr = try self.resolveInst(ty_op.operand); | 7709 | const ptr = try self.resolveInst(ty_op.operand); |
| 7851 | const array_ty = ptr_ty.childType(); | 7710 | const array_ty = ptr_ty.childType(); |
| 7852 | const array_len = array_ty.arrayLen(); | 7711 | const array_len = array_ty.arrayLen(); |
| 7853 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else blk: { | 7712 | |
| 7854 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); | 7713 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 7855 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); | 7714 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 7856 | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); | 7715 | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 7857 | break :blk .{ .stack_offset = stack_offset }; | 7716 | |
| 7858 | }; | 7717 | const result = MCValue{ .stack_offset = stack_offset }; |
| 7859 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 7718 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7860 | } | 7719 | } |
| 7861 | | 7720 | |
| 7862 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | 7721 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 7863 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7722 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7864 | const result: MCValue = if (self.liveness.isUnused(inst)) | 7723 | _ = ty_op; |
| 7865 | .unreach | 7724 | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); |
| 7866 | else | 7725 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7867 | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); | | |
| 7868 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 7869 | } | 7726 | } |
| 7870 | | 7727 | |
| 7871 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | 7728 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7872 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7729 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7873 | if (self.liveness.isUnused(inst)) | | |
| 7874 | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); | | |
| 7875 | | 7730 | |
| 7876 | const src_ty = self.air.typeOf(ty_op.operand); | 7731 | const src_ty = self.air.typeOf(ty_op.operand); |
| 7877 | const dst_ty = self.air.typeOfIndex(inst); | 7732 | const dst_ty = self.air.typeOfIndex(inst); |
| ... | @@ -8255,27 +8110,22 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8255,27 +8110,22 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 8255 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { | 8110 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8256 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; | 8111 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; |
| 8257 | | 8112 | |
| 8258 | const result: MCValue = result: { | 8113 | const ptr_ty = self.air.typeOf(atomic_load.ptr); |
| 8259 | if (self.liveness.isUnused(inst)) break :result .unreach; | 8114 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); |
| 8260 | | 8115 | const ptr_lock = switch (ptr_mcv) { |
| 8261 | const ptr_ty = self.air.typeOf(atomic_load.ptr); | 8116 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8262 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); | 8117 | else => null, |
| 8263 | const ptr_lock = switch (ptr_mcv) { | 8118 | }; |
| 8264 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 8119 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 8265 | else => null, | | |
| 8266 | }; | | |
| 8267 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 8268 | | 8120 | |
| 8269 | const dst_mcv = | 8121 | const dst_mcv = |
| 8270 | if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv)) | 8122 | if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv)) |
| 8271 | ptr_mcv | 8123 | ptr_mcv |
| 8272 | else | 8124 | else |
| 8273 | try self.allocRegOrMem(inst, true); | 8125 | try self.allocRegOrMem(inst, true); |
| 8274 | | 8126 | |
| 8275 | try self.load(dst_mcv, ptr_mcv, ptr_ty); | 8127 | try self.load(dst_mcv, ptr_mcv, ptr_ty); |
| 8276 | break :result dst_mcv; | 8128 | return self.finishAir(inst, dst_mcv, .{ atomic_load.ptr, .none, .none }); |
| 8277 | }; | | |
| 8278 | return self.finishAir(inst, result, .{ atomic_load.ptr, .none, .none }); | | |
| 8279 | } | 8129 | } |
| 8280 | | 8130 | |
| 8281 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { | 8131 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| ... | @@ -8354,122 +8204,123 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8354,122 +8204,123 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 8354 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | 8204 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 8355 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8205 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8356 | const operand = try self.resolveInst(un_op); | 8206 | const operand = try self.resolveInst(un_op); |
| 8357 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { | 8207 | _ = operand; |
| 8358 | _ = operand; | 8208 | return self.fail("TODO implement airTagName for x86_64", .{}); |
| 8359 | return self.fail("TODO implement airTagName for x86_64", .{}); | 8209 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8360 | }; | | |
| 8361 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | | |
| 8362 | } | 8210 | } |
| 8363 | | 8211 | |
| 8364 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | 8212 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8365 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8213 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8366 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | | |
| 8367 | const err_ty = self.air.typeOf(un_op); | | |
| 8368 | const err_mcv = try self.resolveInst(un_op); | | |
| 8369 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); | | |
| 8370 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); | | |
| 8371 | defer self.register_manager.unlockReg(err_lock); | | |
| 8372 | | | |
| 8373 | const addr_reg = try self.register_manager.allocReg(null, gp); | | |
| 8374 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | | |
| 8375 | defer self.register_manager.unlockReg(addr_lock); | | |
| 8376 | | | |
| 8377 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | | |
| 8378 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( | | |
| 8379 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 8380 | 4, // dword alignment | | |
| 8381 | ); | | |
| 8382 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); | | |
| 8383 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ | | |
| 8384 | .base = .ds, | | |
| 8385 | .disp = @intCast(i32, got_addr), | | |
| 8386 | })); | | |
| 8387 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | | |
| 8388 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( | | |
| 8389 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 8390 | 4, // dword alignment | | |
| 8391 | ); | | |
| 8392 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | | |
| 8393 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); | | |
| 8394 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | | |
| 8395 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( | | |
| 8396 | .{ .kind = .const_data, .ty = Type.anyerror }, | | |
| 8397 | 4, // dword alignment | | |
| 8398 | ); | | |
| 8399 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | | |
| 8400 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); | | |
| 8401 | } else { | | |
| 8402 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); | | |
| 8403 | } | | |
| 8404 | | | |
| 8405 | const start_reg = try self.register_manager.allocReg(null, gp); | | |
| 8406 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); | | |
| 8407 | defer self.register_manager.unlockReg(start_lock); | | |
| 8408 | | 8214 | |
| 8409 | const end_reg = try self.register_manager.allocReg(null, gp); | 8215 | const err_ty = self.air.typeOf(un_op); |
| 8410 | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); | 8216 | const err_mcv = try self.resolveInst(un_op); |
| 8411 | defer self.register_manager.unlockReg(end_lock); | 8217 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| | 8218 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| | 8219 | defer self.register_manager.unlockReg(err_lock); |
| 8412 | | 8220 | |
| 8413 | try self.truncateRegister(err_ty, err_reg.to32()); | 8221 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| | 8222 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| | 8223 | defer self.register_manager.unlockReg(addr_lock); |
| 8414 | | 8224 | |
| 8415 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ | 8225 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8416 | .base = addr_reg.to64(), | 8226 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 8417 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, | 8227 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8418 | .disp = 4, | 8228 | 4, // dword alignment |
| 8419 | })); | 8229 | ); |
| 8420 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ | 8230 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 8421 | .base = addr_reg.to64(), | 8231 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 8422 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, | 8232 | .base = .ds, |
| 8423 | .disp = 8, | 8233 | .disp = @intCast(i32, got_addr), |
| 8424 | })); | | |
| 8425 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); | | |
| 8426 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ | | |
| 8427 | .base = addr_reg.to64(), | | |
| 8428 | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, | | |
| 8429 | .disp = 0, | | |
| 8430 | })); | | |
| 8431 | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ | | |
| 8432 | .base = end_reg.to64(), | | |
| 8433 | .disp = -1, | | |
| 8434 | })); | 8234 | })); |
| | 8235 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| | 8236 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| | 8237 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 8238 | 4, // dword alignment |
| | 8239 | ); |
| | 8240 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| | 8241 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| | 8242 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| | 8243 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| | 8244 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 8245 | 4, // dword alignment |
| | 8246 | ); |
| | 8247 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| | 8248 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| | 8249 | } else { |
| | 8250 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| | 8251 | } |
| 8435 | | 8252 | |
| 8436 | const dst_mcv = try self.allocRegOrMem(inst, false); | 8253 | const start_reg = try self.register_manager.allocReg(null, gp); |
| 8437 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ | 8254 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); |
| 8438 | .base = .rbp, | 8255 | defer self.register_manager.unlockReg(start_lock); |
| 8439 | .disp = 0 - dst_mcv.stack_offset, | 8256 | |
| 8440 | }), start_reg.to64()); | 8257 | const end_reg = try self.register_manager.allocReg(null, gp); |
| 8441 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ | 8258 | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); |
| 8442 | .base = .rbp, | 8259 | defer self.register_manager.unlockReg(end_lock); |
| 8443 | .disp = 8 - dst_mcv.stack_offset, | 8260 | |
| 8444 | }), end_reg.to64()); | 8261 | try self.truncateRegister(err_ty, err_reg.to32()); |
| 8445 | break :result dst_mcv; | 8262 | |
| 8446 | }; | 8263 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ |
| 8447 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8264 | .base = addr_reg.to64(), |
| | 8265 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| | 8266 | .disp = 4, |
| | 8267 | })); |
| | 8268 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ |
| | 8269 | .base = addr_reg.to64(), |
| | 8270 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| | 8271 | .disp = 8, |
| | 8272 | })); |
| | 8273 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); |
| | 8274 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ |
| | 8275 | .base = addr_reg.to64(), |
| | 8276 | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, |
| | 8277 | .disp = 0, |
| | 8278 | })); |
| | 8279 | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ |
| | 8280 | .base = end_reg.to64(), |
| | 8281 | .disp = -1, |
| | 8282 | })); |
| | 8283 | |
| | 8284 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 8285 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 8286 | .base = .rbp, |
| | 8287 | .disp = 0 - dst_mcv.stack_offset, |
| | 8288 | }), start_reg.to64()); |
| | 8289 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 8290 | .base = .rbp, |
| | 8291 | .disp = 8 - dst_mcv.stack_offset, |
| | 8292 | }), end_reg.to64()); |
| | 8293 | |
| | 8294 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 8448 | } | 8295 | } |
| 8449 | | 8296 | |
| 8450 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { | 8297 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 8451 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8298 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8452 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSplat for x86_64", .{}); | 8299 | _ = ty_op; |
| 8453 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 8300 | return self.fail("TODO implement airSplat for x86_64", .{}); |
| | 8301 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8454 | } | 8302 | } |
| 8455 | | 8303 | |
| 8456 | fn airSelect(self: *Self, inst: Air.Inst.Index) !void { | 8304 | fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 8457 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8305 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8458 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 8306 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 8459 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSelect for x86_64", .{}); | 8307 | _ = extra; |
| 8460 | return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); | 8308 | return self.fail("TODO implement airSelect for x86_64", .{}); |
| | 8309 | //return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 8461 | } | 8310 | } |
| 8462 | | 8311 | |
| 8463 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 8312 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 8464 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8313 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8465 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airShuffle for x86_64", .{}); | 8314 | _ = ty_op; |
| 8466 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 8315 | return self.fail("TODO implement airShuffle for x86_64", .{}); |
| | 8316 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8467 | } | 8317 | } |
| 8468 | | 8318 | |
| 8469 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | 8319 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 8470 | const reduce = self.air.instructions.items(.data)[inst].reduce; | 8320 | const reduce = self.air.instructions.items(.data)[inst].reduce; |
| 8471 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airReduce for x86_64", .{}); | 8321 | _ = reduce; |
| 8472 | return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); | 8322 | return self.fail("TODO implement airReduce for x86_64", .{}); |
| | 8323 | //return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); |
| 8473 | } | 8324 | } |
| 8474 | | 8325 | |
| 8475 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 8326 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -8479,8 +8330,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8479,8 +8330,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8479 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 8330 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 8480 | const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); | 8331 | const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); |
| 8481 | const abi_align = result_ty.abiAlignment(self.target.*); | 8332 | const abi_align = result_ty.abiAlignment(self.target.*); |
| 8482 | const result: MCValue = res: { | 8333 | const result: MCValue = result: { |
| 8483 | if (self.liveness.isUnused(inst)) break :res MCValue.unreach; | | |
| 8484 | switch (result_ty.zigTypeTag()) { | 8334 | switch (result_ty.zigTypeTag()) { |
| 8485 | .Struct => { | 8335 | .Struct => { |
| 8486 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 8336 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| ... | @@ -8571,7 +8421,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8571,7 +8421,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8571 | }; | 8421 | }; |
| 8572 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); | 8422 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); |
| 8573 | } | 8423 | } |
| 8574 | break :res .{ .stack_offset = stack_offset }; | 8424 | break :result .{ .stack_offset = stack_offset }; |
| 8575 | }, | 8425 | }, |
| 8576 | .Array => { | 8426 | .Array => { |
| 8577 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 8427 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| ... | @@ -8587,7 +8437,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8587,7 +8437,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8587 | const elem_off = @intCast(i32, elem_size * elem_i); | 8437 | const elem_off = @intCast(i32, elem_size * elem_i); |
| 8588 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); | 8438 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); |
| 8589 | } | 8439 | } |
| 8590 | break :res MCValue{ .stack_offset = stack_offset }; | 8440 | break :result MCValue{ .stack_offset = stack_offset }; |
| 8591 | }, | 8441 | }, |
| 8592 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), | 8442 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), |
| 8593 | else => unreachable, | 8443 | else => unreachable, |
| ... | @@ -8607,11 +8457,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8607,11 +8457,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8607 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | 8457 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8608 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 8458 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8609 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 8459 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 8610 | const result: MCValue = res: { | 8460 | _ = extra; |
| 8611 | if (self.liveness.isUnused(inst)) break :res MCValue.unreach; | 8461 | return self.fail("TODO implement airAggregateInit for x86_64", .{}); |
| 8612 | return self.fail("TODO implement airAggregateInit for x86_64", .{}); | 8462 | //return self.finishAir(inst, result, .{ extra.init, .none, .none }); |
| 8613 | }; | | |
| 8614 | return self.finishAir(inst, result, .{ extra.init, .none, .none }); | | |
| 8615 | } | 8463 | } |
| 8616 | | 8464 | |
| 8617 | fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { | 8465 | fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -8622,10 +8470,9 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8622,10 +8470,9 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| 8622 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | 8470 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 8623 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8471 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8624 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 8472 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 8625 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { | 8473 | _ = extra; |
| 8626 | return self.fail("TODO implement airMulAdd for x86_64", .{}); | 8474 | return self.fail("TODO implement airMulAdd for x86_64", .{}); |
| 8627 | }; | 8475 | //return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 8628 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); | | |
| 8629 | } | 8476 | } |
| 8630 | | 8477 | |
| 8631 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | 8478 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |