authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-16 23:17:48+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-19 12:06:30+01:00
log67e334663399d1dcf6fc8c3fa9a896494f1af652
tree32457eadb6761b15adbd1c59c70838117cca764d
parent23915c2c444b257009816d00c15d6f2475a161b0
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: move add and sub to new binOp lowering mechanism


1 files changed, 286 insertions(+), 39 deletions(-)

src/arch/arm/CodeGen.zig+286-39
......@@ -502,10 +502,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
502502
503503 switch (air_tags[inst]) {
504504 // zig fmt: off
505 .add, .ptr_add => try self.airAdd(inst),
505 .add, .ptr_add => try self.airBinOp(inst),
506506 .addwrap => try self.airAddWrap(inst),
507507 .add_sat => try self.airAddSat(inst),
508 .sub, .ptr_sub => try self.airSub(inst),
508 .sub, .ptr_sub => try self.airBinOp(inst),
509509 .subwrap => try self.airSubWrap(inst),
510510 .sub_sat => try self.airSubSat(inst),
511511 .mul => try self.airMul(inst),
......@@ -943,9 +943,15 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
943943 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
944944}
945945
946fn airAdd(self: *Self, inst: Air.Inst.Index) !void {
946fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
947 const tag = self.air.instructions.items(.tag)[inst];
947948 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
948 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .add);
949 const lhs = try self.resolveInst(bin_op.lhs);
950 const rhs = try self.resolveInst(bin_op.rhs);
951 const lhs_ty = self.air.typeOf(bin_op.lhs);
952 const rhs_ty = self.air.typeOf(bin_op.rhs);
953
954 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
949955 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
950956}
951957
......@@ -961,12 +967,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
961967 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
962968}
963969
964fn airSub(self: *Self, inst: Air.Inst.Index) !void {
965 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
966 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .sub);
967 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
968}
969
970970fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
971971 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
972972 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
......@@ -1311,18 +1311,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
13111311 assert(offset_mcv == .register); // result of multiplication should always be register
13121312 self.register_manager.freezeRegs(&.{offset_mcv.register});
13131313
1314 const addr_reg = try self.register_manager.allocReg(null);
1315 self.register_manager.freezeRegs(&.{addr_reg});
1316 defer self.register_manager.unfreezeRegs(&.{addr_reg});
1317
1318 try self.genBinOpCode(addr_reg, base_mcv, offset_mcv, false, .add, .unsigned);
1314 const addr_mcv = try self.binOp(.add, null, base_mcv, offset_mcv, Type.usize, Type.usize);
13191315
13201316 // At this point in time, neither the base register
13211317 // nor the offset register contains any valuable data
13221318 // anymore.
13231319 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
13241320
1325 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1321 try self.load(dst_mcv, addr_mcv, slice_ptr_field_type);
13261322
13271323 break :result dst_mcv;
13281324 },
......@@ -1652,16 +1648,16 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
16521648 self.register_manager.freezeRegs(&.{addr_reg});
16531649 defer self.register_manager.unfreezeRegs(&.{addr_reg});
16541650
1655 const dst_reg = try self.register_manager.allocReg(inst);
1656 try self.genBinOpCode(
1657 dst_reg,
1651 const dest = try self.binOp(
1652 .add,
1653 null,
16581654 .{ .register = addr_reg },
16591655 .{ .register = offset_reg },
1660 false,
1661 .add,
1662 .unsigned,
1656 Type.usize,
1657 Type.usize,
16631658 );
1664 break :result MCValue{ .register = dst_reg };
1659
1660 break :result dest;
16651661 },
16661662 }
16671663 };
......@@ -1699,6 +1695,273 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
16991695 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
17001696}
17011697
1698/// Don't call this function directly. Use binOp instead.
1699///
1700/// Calling this function signals an intention to generate a Mir
1701/// instruction of the form
1702///
1703/// op dest, lhs, rhs
1704///
1705/// Asserts that generating an instruction of that form is possible.
1706fn binOpRegister(
1707 self: *Self,
1708 tag: Air.Inst.Tag,
1709 maybe_inst: ?Air.Inst.Index,
1710 lhs: MCValue,
1711 rhs: MCValue,
1712 lhs_ty: Type,
1713 rhs_ty: Type,
1714) !MCValue {
1715 const lhs_is_register = lhs == .register;
1716 const rhs_is_register = rhs == .register;
1717
1718 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1719 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
1720
1721 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1722
1723 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1724 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
1725 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1726 break :inst Air.refToIndex(bin_op.lhs).?;
1727 } else null;
1728
1729 const reg = try self.register_manager.allocReg(track_inst);
1730 self.register_manager.freezeRegs(&.{reg});
1731
1732 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1733
1734 break :blk reg;
1735 };
1736 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1737
1738 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1739 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
1740 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1741 break :inst Air.refToIndex(bin_op.rhs).?;
1742 } else null;
1743
1744 const reg = try self.register_manager.allocReg(track_inst);
1745 self.register_manager.freezeRegs(&.{reg});
1746
1747 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1748
1749 break :blk reg;
1750 };
1751 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
1752
1753 const dest_reg = if (maybe_inst) |inst| blk: {
1754 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1755
1756 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1757 break :blk lhs_reg;
1758 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1759 break :blk rhs_reg;
1760 } else {
1761 break :blk try self.register_manager.allocReg(inst);
1762 }
1763 } else try self.register_manager.allocReg(null);
1764
1765 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1766 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1767
1768 const mir_tag: Mir.Inst.Tag = switch (tag) {
1769 .add, .ptr_add => .add,
1770 .sub, .ptr_sub => .sub,
1771 else => unreachable,
1772 };
1773 const mir_data: Mir.Inst.Data = switch (tag) {
1774 .add,
1775 .sub,
1776 .ptr_add,
1777 .ptr_sub,
1778 => .{ .rr_op = .{
1779 .rd = dest_reg,
1780 .rn = lhs_reg,
1781 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
1782 } },
1783 else => unreachable,
1784 };
1785
1786 _ = try self.addInst(.{
1787 .tag = mir_tag,
1788 .data = mir_data,
1789 });
1790
1791 return MCValue{ .register = dest_reg };
1792}
1793
1794/// Don't call this function directly. Use binOp instead.
1795///
1796/// Calling this function signals an intention to generate a Mir
1797/// instruction of the form
1798///
1799/// op dest, lhs, #rhs_imm
1800///
1801/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
1802/// rhs and vice versa. This parameter is only used when maybe_inst !=
1803/// null.
1804///
1805/// Asserts that generating an instruction of that form is possible.
1806fn binOpImmediate(
1807 self: *Self,
1808 tag: Air.Inst.Tag,
1809 maybe_inst: ?Air.Inst.Index,
1810 lhs: MCValue,
1811 rhs: MCValue,
1812 lhs_ty: Type,
1813 lhs_and_rhs_swapped: bool,
1814) !MCValue {
1815 const lhs_is_register = lhs == .register;
1816
1817 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1818
1819 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1820
1821 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1822 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
1823 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1824 break :inst Air.refToIndex(
1825 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,
1826 ).?;
1827 } else null;
1828
1829 const reg = try self.register_manager.allocReg(track_inst);
1830 self.register_manager.freezeRegs(&.{reg});
1831
1832 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1833
1834 break :blk reg;
1835 };
1836 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1837
1838 const dest_reg = if (maybe_inst) |inst| blk: {
1839 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1840
1841 if (lhs_is_register and self.reuseOperand(
1842 inst,
1843 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,
1844 if (lhs_and_rhs_swapped) 1 else 0,
1845 lhs,
1846 )) {
1847 break :blk lhs_reg;
1848 } else {
1849 break :blk try self.register_manager.allocReg(inst);
1850 }
1851 } else try self.register_manager.allocReg(null);
1852
1853 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1854
1855 const mir_tag: Mir.Inst.Tag = switch (tag) {
1856 .add => .add,
1857 .sub => .sub,
1858 else => unreachable,
1859 };
1860 const mir_data: Mir.Inst.Data = switch (tag) {
1861 .add,
1862 .sub,
1863 => .{ .rr_op = .{
1864 .rd = dest_reg,
1865 .rn = lhs_reg,
1866 .op = Instruction.Operand.fromU32(rhs.immediate).?,
1867 } },
1868 else => unreachable,
1869 };
1870
1871 _ = try self.addInst(.{
1872 .tag = mir_tag,
1873 .data = mir_data,
1874 });
1875
1876 return MCValue{ .register = dest_reg };
1877}
1878
1879/// For all your binary operation needs, this function will generate
1880/// the corresponding Mir instruction(s). Returns the location of the
1881/// result.
1882///
1883/// If the binary operation itself happens to be an Air instruction,
1884/// pass the corresponding index in the inst parameter. That helps
1885/// this function do stuff like reusing operands.
1886///
1887/// This function does not do any lowering to Mir itself, but instead
1888/// looks at the lhs and rhs and determines which kind of lowering
1889/// would be best suitable and then delegates the lowering to other
1890/// functions.
1891fn binOp(
1892 self: *Self,
1893 tag: Air.Inst.Tag,
1894 maybe_inst: ?Air.Inst.Index,
1895 lhs: MCValue,
1896 rhs: MCValue,
1897 lhs_ty: Type,
1898 rhs_ty: Type,
1899) !MCValue {
1900 switch (tag) {
1901 .add,
1902 .sub,
1903 => {
1904 switch (lhs_ty.zigTypeTag()) {
1905 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
1906 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
1907 .Int => {
1908 assert(lhs_ty.eql(rhs_ty));
1909 const int_info = lhs_ty.intInfo(self.target.*);
1910 if (int_info.bits <= 32) {
1911 // Only say yes if the operation is
1912 // commutative, i.e. we can swap both of the
1913 // operands
1914 const lhs_immediate_ok = switch (tag) {
1915 .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
1916 .sub => false,
1917 else => unreachable,
1918 };
1919 const rhs_immediate_ok = switch (tag) {
1920 .add,
1921 .sub,
1922 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
1923 else => unreachable,
1924 };
1925
1926 if (rhs_immediate_ok) {
1927 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1928 } else if (lhs_immediate_ok) {
1929 // swap lhs and rhs
1930 return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true);
1931 } else {
1932 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1933 }
1934 } else {
1935 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
1936 }
1937 },
1938 else => unreachable,
1939 }
1940 },
1941 .ptr_add,
1942 .ptr_sub,
1943 => {
1944 switch (lhs_ty.zigTypeTag()) {
1945 .Pointer => {
1946 const ptr_ty = lhs_ty;
1947 const pointee_ty = switch (ptr_ty.ptrSize()) {
1948 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
1949 else => ptr_ty.childType(),
1950 };
1951
1952 if (pointee_ty.abiSize(self.target.*) > 1) {
1953 return self.fail("TODO ptr_add, ptr_sub with more element sizes", .{});
1954 }
1955
1956 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1957 },
1958 else => unreachable,
1959 }
1960 },
1961 else => unreachable,
1962 }
1963}
1964
17021965fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
17031966 return switch (mcv) {
17041967 .none => unreachable,
......@@ -1730,8 +1993,6 @@ fn genBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air
17301993 const ty = self.air.typeOf(op_lhs);
17311994
17321995 switch (ty.zigTypeTag()) {
1733 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
1734 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
17351996 .Bool => {
17361997 return self.genBinIntOp(inst, op_lhs, op_rhs, op, 1, .unsigned);
17371998 },
......@@ -1896,7 +2157,6 @@ fn genBinOpCode(
18962157 };
18972158
18982159 switch (op) {
1899 .add,
19002160 .bool_and,
19012161 .bit_and,
19022162 .bool_or,
......@@ -1905,7 +2165,6 @@ fn genBinOpCode(
19052165 .xor,
19062166 => {
19072167 const tag: Mir.Inst.Tag = switch (op) {
1908 .add => .add,
19092168 .bool_and, .bit_and => .@"and",
19102169 .bool_or, .bit_or => .orr,
19112170 .not, .xor => .eor,
......@@ -1921,18 +2180,6 @@ fn genBinOpCode(
19212180 } },
19222181 });
19232182 },
1924 .sub => {
1925 const tag: Mir.Inst.Tag = if (swap_lhs_and_rhs) .rsb else .sub;
1926
1927 _ = try self.addInst(.{
1928 .tag = tag,
1929 .data = .{ .rr_op = .{
1930 .rd = dst_reg,
1931 .rn = op1,
1932 .op = operand,
1933 } },
1934 });
1935 },
19362183 .cmp_eq => {
19372184 _ = try self.addInst(.{
19382185 .tag = .cmp,