authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-19 11:57:56+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-19 12:12:29+01:00
log669603029e5d484411f8ed8a6d6e48d9f3a344b1
treeb2d03a6b15be1c73e51975a5328d7436ebb21116
parentc29bf2f51ae64456edd92bc6e37a6a8d8c7ba44e
signature Commit is signed but in an unrecognized format.

stage2 ARM: implement airCmp with binOp lowering mechanism


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

src/arch/arm/CodeGen.zig+66-123
...@@ -1783,17 +1783,20 @@ fn binOpRegister(...@@ -1783,17 +1783,20 @@ fn binOpRegister(
1783 };1783 };
1784 defer self.register_manager.unfreezeRegs(&.{rhs_reg});1784 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
17851785
1786 const dest_reg = if (maybe_inst) |inst| blk: {1786 const dest_reg = switch (tag) {
1787 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1787 .cmp_eq => .r0, // cmp has no destination regardless
1788 else => if (maybe_inst) |inst| blk: {
1789 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
17881790
1789 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {1791 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1790 break :blk lhs_reg;1792 break :blk lhs_reg;
1791 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1793 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1792 break :blk rhs_reg;1794 break :blk rhs_reg;
1793 } else {1795 } else {
1794 break :blk try self.register_manager.allocReg(inst);1796 break :blk try self.register_manager.allocReg(inst);
1795 }1797 }
1796 } else try self.register_manager.allocReg(null);1798 } else try self.register_manager.allocReg(null),
1799 };
17971800
1798 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);1801 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1799 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);1802 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
...@@ -1801,6 +1804,7 @@ fn binOpRegister(...@@ -1801,6 +1804,7 @@ fn binOpRegister(
1801 const mir_tag: Mir.Inst.Tag = switch (tag) {1804 const mir_tag: Mir.Inst.Tag = switch (tag) {
1802 .add, .ptr_add => .add,1805 .add, .ptr_add => .add,
1803 .sub, .ptr_sub => .sub,1806 .sub, .ptr_sub => .sub,
1807 .cmp_eq => .cmp,
1804 .mul => .mul,1808 .mul => .mul,
1805 .bit_and,1809 .bit_and,
1806 .bool_and,1810 .bool_and,
...@@ -1823,6 +1827,7 @@ fn binOpRegister(...@@ -1823,6 +1827,7 @@ fn binOpRegister(
1823 const mir_data: Mir.Inst.Data = switch (tag) {1827 const mir_data: Mir.Inst.Data = switch (tag) {
1824 .add,1828 .add,
1825 .sub,1829 .sub,
1830 .cmp_eq,
1826 .bit_and,1831 .bit_and,
1827 .bool_and,1832 .bool_and,
1828 .bit_or,1833 .bit_or,
...@@ -1904,26 +1909,30 @@ fn binOpImmediate(...@@ -1904,26 +1909,30 @@ fn binOpImmediate(
1904 };1909 };
1905 defer self.register_manager.unfreezeRegs(&.{lhs_reg});1910 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
19061911
1907 const dest_reg = if (maybe_inst) |inst| blk: {1912 const dest_reg = switch (tag) {
1908 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1913 .cmp_eq => .r0, // cmp has no destination reg
1914 else => if (maybe_inst) |inst| blk: {
1915 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
19091916
1910 if (lhs_is_register and self.reuseOperand(1917 if (lhs_is_register and self.reuseOperand(
1911 inst,1918 inst,
1912 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1919 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,
1913 if (lhs_and_rhs_swapped) 1 else 0,1920 if (lhs_and_rhs_swapped) 1 else 0,
1914 lhs,1921 lhs,
1915 )) {1922 )) {
1916 break :blk lhs_reg;1923 break :blk lhs_reg;
1917 } else {1924 } else {
1918 break :blk try self.register_manager.allocReg(inst);1925 break :blk try self.register_manager.allocReg(inst);
1919 }1926 }
1920 } else try self.register_manager.allocReg(null);1927 } else try self.register_manager.allocReg(null),
1928 };
19211929
1922 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);1930 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
19231931
1924 const mir_tag: Mir.Inst.Tag = switch (tag) {1932 const mir_tag: Mir.Inst.Tag = switch (tag) {
1925 .add => .add,1933 .add => .add,
1926 .sub => .sub,1934 .sub => .sub,
1935 .cmp_eq => .cmp,
1927 .bit_and,1936 .bit_and,
1928 .bool_and,1937 .bool_and,
1929 => .@"and",1938 => .@"and",
...@@ -1945,6 +1954,7 @@ fn binOpImmediate(...@@ -1945,6 +1954,7 @@ fn binOpImmediate(
1945 const mir_data: Mir.Inst.Data = switch (tag) {1954 const mir_data: Mir.Inst.Data = switch (tag) {
1946 .add,1955 .add,
1947 .sub,1956 .sub,
1957 .cmp_eq,
1948 .bit_and,1958 .bit_and,
1949 .bool_and,1959 .bool_and,
1950 .bit_or,1960 .bit_or,
...@@ -1999,6 +2009,7 @@ fn binOp(...@@ -1999,6 +2009,7 @@ fn binOp(
1999 switch (tag) {2009 switch (tag) {
2000 .add,2010 .add,
2001 .sub,2011 .sub,
2012 .cmp_eq,
2002 => {2013 => {
2003 switch (lhs_ty.zigTypeTag()) {2014 switch (lhs_ty.zigTypeTag()) {
2004 .Float => return self.fail("TODO ARM binary operations on floats", .{}),2015 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
...@@ -2012,12 +2023,15 @@ fn binOp(...@@ -2012,12 +2023,15 @@ fn binOp(
2012 // operands2023 // operands
2013 const lhs_immediate_ok = switch (tag) {2024 const lhs_immediate_ok = switch (tag) {
2014 .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,2025 .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
2015 .sub => false,2026 .sub,
2027 .cmp_eq,
2028 => false,
2016 else => unreachable,2029 else => unreachable,
2017 };2030 };
2018 const rhs_immediate_ok = switch (tag) {2031 const rhs_immediate_ok = switch (tag) {
2019 .add,2032 .add,
2020 .sub,2033 .sub,
2034 .cmp_eq,
2021 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,2035 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
2022 else => unreachable,2036 else => unreachable,
2023 };2037 };
...@@ -2150,31 +2164,6 @@ fn binOp(...@@ -2150,31 +2164,6 @@ fn binOp(
2150 }2164 }
2151}2165}
21522166
2153fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
2154 return switch (mcv) {
2155 .none => unreachable,
2156 .undef => unreachable,
2157 .dead, .unreach => unreachable,
2158 .compare_flags_unsigned => unreachable,
2159 .compare_flags_signed => unreachable,
2160 .ptr_stack_offset => unreachable,
2161 .ptr_embedded_in_code => unreachable,
2162 .immediate => |imm| blk: {
2163 if (imm > std.math.maxInt(u32)) return self.fail("TODO ARM binary arithmetic immediate larger than u32", .{});
2164
2165 // Load immediate into register if it doesn't fit
2166 // in an operand
2167 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) == null;
2168 },
2169 .register => true,
2170 .stack_offset,
2171 .stack_argument_offset,
2172 .embedded_in_code,
2173 .memory,
2174 => true,
2175 };
2176}
2177
2178fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {2167fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {
2179 switch (abi_size) {2168 switch (abi_size) {
2180 1, 3, 4 => {2169 1, 3, 4 => {
...@@ -2548,84 +2537,38 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2548,84 +2537,38 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2548 const rhs = try self.resolveInst(bin_op.rhs);2537 const rhs = try self.resolveInst(bin_op.rhs);
2549 const lhs_ty = self.air.typeOf(bin_op.lhs);2538 const lhs_ty = self.air.typeOf(bin_op.lhs);
25502539
2551 if (lhs_ty.abiSize(self.target.*) > 4) {2540 switch (lhs_ty.zigTypeTag()) {
2552 return self.fail("TODO cmp for types with size > 4", .{});2541 .Vector => return self.fail("TODO ARM cmp vectors", .{}),
2553 }2542 .Optional => return self.fail("TODO ARM cmp optionals", .{}),
25542543 .Float => return self.fail("TODO ARM cmp floats", .{}),
2555 const signedness: std.builtin.Signedness = blk: {2544 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {
2556 // by default we tell the operand type is unsigned (i.e. bools and enum values)2545 var int_buffer: Type.Payload.Bits = undefined;
2557 if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned;2546 const int_ty = switch (lhs_ty.zigTypeTag()) {
25582547 .Enum => lhs_ty.intTagType(&int_buffer),
2559 // incase of an actual integer, we emit the correct signedness2548 .Int => lhs_ty,
2560 break :blk lhs_ty.intInfo(self.target.*).signedness;2549 .Bool => Type.initTag(.u1),
2561 };2550 .Pointer => Type.usize,
25622551 .ErrorSet => Type.initTag(.u16),
2563 try self.spillCompareFlagsIfOccupied();2552 else => unreachable,
2564 self.compare_flags_inst = inst;2553 };
2565
2566 const lhs_is_register = lhs == .register;
2567 const rhs_is_register = rhs == .register;
2568 // lhs should always be a register
2569 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);
25702554
2571 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});2555 const int_info = int_ty.intInfo(self.target.*);
2572 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});2556 if (int_info.bits <= 32) {
2573 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});2557 try self.spillCompareFlagsIfOccupied();
2574 defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register});2558 self.compare_flags_inst = inst;
25752559
2576 var lhs_mcv = lhs;2560 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);
2577 var rhs_mcv = rhs;
25782561
2579 // Allocate registers2562 break :result switch (int_info.signedness) {
2580 if (rhs_should_be_register) {2563 .signed => MCValue{ .compare_flags_signed = op },
2581 if (!lhs_is_register and !rhs_is_register) {2564 .unsigned => MCValue{ .compare_flags_unsigned = op },
2582 const regs = try self.register_manager.allocRegs(2, .{2565 };
2583 Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?,2566 } else {
2584 });2567 return self.fail("TODO ARM cmp for ints > 32 bits", .{});
2585 lhs_mcv = MCValue{ .register = regs[0] };2568 }
2586 rhs_mcv = MCValue{ .register = regs[1] };2569 },
2587 } else if (!rhs_is_register) {2570 else => unreachable,
2588 const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?;
2589 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
2590 } else if (!lhs_is_register) {
2591 const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
2592 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
2593 }
2594 } else {
2595 if (!lhs_is_register) {
2596 const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
2597 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
2598 }
2599 }
2600
2601 // Move the operands to the newly allocated registers
2602 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2603 if (lhs_mcv == .register and !lhs_is_register) {
2604 try self.genSetReg(lhs_ty, lhs_mcv.register, lhs);
2605 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs);
2606 }
2607 if (rhs_mcv == .register and !rhs_is_register) {
2608 try self.genSetReg(lhs_ty, rhs_mcv.register, rhs);
2609 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs);
2610 }2571 }
2611
2612 _ = try self.addInst(.{
2613 .tag = .cmp,
2614 .data = .{ .rr_op = .{
2615 .rd = undefined,
2616 .rn = lhs_mcv.register,
2617 .op = switch (rhs_mcv) {
2618 .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?,
2619 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
2620 else => unreachable,
2621 },
2622 } },
2623 });
2624
2625 break :result switch (signedness) {
2626 .signed => MCValue{ .compare_flags_signed = op },
2627 .unsigned => MCValue{ .compare_flags_unsigned = op },
2628 };
2629 };2572 };
2630 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2573 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2631}2574}