authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-08-20 23:17:46+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-08-20 23:17:46+02:00
logf9e50a5830ab9a9ce0cb3e7eeb5e8da845926867
tree93e30c71625b51fea7215995f83e7b6a23efe32f
parent7aecf90d2eeead6796569713635f523cbe17295e
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: implement bitshifting for 32-bit integers


1 files changed, 66 insertions(+), 4 deletions(-)

src/codegen.zig+66-4
...@@ -1592,15 +1592,53 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1592,15 +1592,53 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1592 }1592 }
15931593
1594 fn genArmBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: Air.Inst.Tag) !MCValue {1594 fn genArmBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: Air.Inst.Tag) !MCValue {
1595 // In the case of bitshifts, the type of rhs is different
1596 // from the resulting type
1597 const ty = self.air.typeOf(op_lhs);
1598
1599 switch (ty.zigTypeTag()) {
1600 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
1601 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
1602 .Bool => {
1603 return self.genArmBinIntOp(inst, op_lhs, op_rhs, op, 1, .unsigned);
1604 },
1605 .Int => {
1606 const int_info = ty.intInfo(self.target.*);
1607 return self.genArmBinIntOp(inst, op_lhs, op_rhs, op, int_info.bits, int_info.signedness);
1608 },
1609 else => unreachable,
1610 }
1611 }
1612
1613 fn genArmBinIntOp(
1614 self: *Self,
1615 inst: Air.Inst.Index,
1616 op_lhs: Air.Inst.Ref,
1617 op_rhs: Air.Inst.Ref,
1618 op: Air.Inst.Tag,
1619 bits: u16,
1620 signedness: std.builtin.Signedness,
1621 ) !MCValue {
1622 if (bits > 32) {
1623 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
1624 }
1625
1595 const lhs = try self.resolveInst(op_lhs);1626 const lhs = try self.resolveInst(op_lhs);
1596 const rhs = try self.resolveInst(op_rhs);1627 const rhs = try self.resolveInst(op_rhs);
15971628
1598 const lhs_is_register = lhs == .register;1629 const lhs_is_register = lhs == .register;
1599 const rhs_is_register = rhs == .register;1630 const rhs_is_register = rhs == .register;
1600 const lhs_should_be_register = try self.armOperandShouldBeRegister(lhs);1631 const lhs_should_be_register = switch (op) {
1632 .shr, .shl => true,
1633 else => try self.armOperandShouldBeRegister(lhs),
1634 };
1601 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);1635 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);
1602 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs);1636 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs);
1603 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs);1637 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs);
1638 const can_swap_lhs_and_rhs = switch (op) {
1639 .shr, .shl => false,
1640 else => true,
1641 };
16041642
1605 // Destination must be a register1643 // Destination must be a register
1606 var dst_mcv: MCValue = undefined;1644 var dst_mcv: MCValue = undefined;
...@@ -1617,7 +1655,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1617,7 +1655,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1617 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);1655 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
1618 }1656 }
1619 dst_mcv = lhs;1657 dst_mcv = lhs;
1620 } else if (reuse_rhs) {1658 } else if (reuse_rhs and can_swap_lhs_and_rhs) {
1621 // Allocate 0 or 1 registers1659 // Allocate 0 or 1 registers
1622 if (!lhs_is_register and lhs_should_be_register) {1660 if (!lhs_is_register and lhs_should_be_register) {
1623 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{rhs.register}) };1661 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{rhs.register}) };
...@@ -1656,7 +1694,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1656,7 +1694,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1656 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };1694 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1657 lhs_mcv = dst_mcv;1695 lhs_mcv = dst_mcv;
1658 }1696 }
1659 } else if (rhs_should_be_register) {1697 } else if (rhs_should_be_register and can_swap_lhs_and_rhs) {
1660 // LHS is immediate1698 // LHS is immediate
1661 if (rhs_is_register) {1699 if (rhs_is_register) {
1662 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };1700 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
...@@ -1683,6 +1721,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1683,6 +1721,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1683 rhs_mcv,1721 rhs_mcv,
1684 swap_lhs_and_rhs,1722 swap_lhs_and_rhs,
1685 op,1723 op,
1724 signedness,
1686 );1725 );
1687 return dst_mcv;1726 return dst_mcv;
1688 }1727 }
...@@ -1694,6 +1733,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1694,6 +1733,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1694 rhs_mcv: MCValue,1733 rhs_mcv: MCValue,
1695 swap_lhs_and_rhs: bool,1734 swap_lhs_and_rhs: bool,
1696 op: Air.Inst.Tag,1735 op: Air.Inst.Tag,
1736 signedness: std.builtin.Signedness,
1697 ) !void {1737 ) !void {
1698 assert(lhs_mcv == .register or rhs_mcv == .register);1738 assert(lhs_mcv == .register or rhs_mcv == .register);
16991739
...@@ -1739,6 +1779,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1739,6 +1779,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1739 .cmp_eq => {1779 .cmp_eq => {
1740 writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, op1, operand).toU32());1780 writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, op1, operand).toU32());
1741 },1781 },
1782 .shl => {
1783 assert(!swap_lhs_and_rhs);
1784 const shift_amout = switch (operand) {
1785 .Register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)),
1786 .Immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)),
1787 };
1788 writeInt(u32, try self.code.addManyAsArray(4), Instruction.lsl(.al, dst_reg, op1, shift_amout).toU32());
1789 },
1790 .shr => {
1791 assert(!swap_lhs_and_rhs);
1792 const shift_amout = switch (operand) {
1793 .Register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)),
1794 .Immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)),
1795 };
1796
1797 const shr = switch (signedness) {
1798 .signed => Instruction.asr,
1799 .unsigned => Instruction.lsr,
1800 };
1801 writeInt(u32, try self.code.addManyAsArray(4), shr(.al, dst_reg, op1, shift_amout).toU32());
1802 },
1742 else => unreachable, // not a binary instruction1803 else => unreachable, // not a binary instruction
1743 }1804 }
1744 }1805 }
...@@ -2989,7 +3050,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2989,7 +3050,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2989 }3050 }
29903051
2991 // The destination register is not present in the cmp instruction3052 // The destination register is not present in the cmp instruction
2992 try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq);3053 // The signedness of the integer does not matter for the cmp instruction
3054 try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined);
29933055
2994 break :result switch (ty.isSignedInt()) {3056 break :result switch (ty.isSignedInt()) {
2995 true => MCValue{ .compare_flags_signed = op },3057 true => MCValue{ .compare_flags_signed = op },