| ... | ... | @@ -1783,17 +1783,20 @@ fn binOpRegister( |
| 1783 | 1783 | }; |
| 1784 | 1784 | defer self.register_manager.unfreezeRegs(&.{rhs_reg}); |
| 1785 | 1785 | |
| 1786 | | const dest_reg = if (maybe_inst) |inst| blk: { |
| 1787 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1786 | const dest_reg = switch (tag) { |
| 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; |
| 1788 | 1790 | |
| 1789 | | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { |
| 1790 | | break :blk lhs_reg; |
| 1791 | | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1792 | | break :blk rhs_reg; |
| 1793 | | } else { |
| 1794 | | break :blk try self.register_manager.allocReg(inst); |
| 1795 | | } |
| 1796 | | } else try self.register_manager.allocReg(null); |
| 1791 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { |
| 1792 | break :blk lhs_reg; |
| 1793 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1794 | break :blk rhs_reg; |
| 1795 | } else { |
| 1796 | break :blk try self.register_manager.allocReg(inst); |
| 1797 | } |
| 1798 | } else try self.register_manager.allocReg(null), |
| 1799 | }; |
| 1797 | 1800 | |
| 1798 | 1801 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1799 | 1802 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| ... | ... | @@ -1801,6 +1804,7 @@ fn binOpRegister( |
| 1801 | 1804 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1802 | 1805 | .add, .ptr_add => .add, |
| 1803 | 1806 | .sub, .ptr_sub => .sub, |
| 1807 | .cmp_eq => .cmp, |
| 1804 | 1808 | .mul => .mul, |
| 1805 | 1809 | .bit_and, |
| 1806 | 1810 | .bool_and, |
| ... | ... | @@ -1823,6 +1827,7 @@ fn binOpRegister( |
| 1823 | 1827 | const mir_data: Mir.Inst.Data = switch (tag) { |
| 1824 | 1828 | .add, |
| 1825 | 1829 | .sub, |
| 1830 | .cmp_eq, |
| 1826 | 1831 | .bit_and, |
| 1827 | 1832 | .bool_and, |
| 1828 | 1833 | .bit_or, |
| ... | ... | @@ -1904,26 +1909,30 @@ fn binOpImmediate( |
| 1904 | 1909 | }; |
| 1905 | 1910 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1906 | 1911 | |
| 1907 | | const dest_reg = if (maybe_inst) |inst| blk: { |
| 1908 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1912 | const dest_reg = switch (tag) { |
| 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; |
| 1909 | 1916 | |
| 1910 | | if (lhs_is_register and self.reuseOperand( |
| 1911 | | inst, |
| 1912 | | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, |
| 1913 | | if (lhs_and_rhs_swapped) 1 else 0, |
| 1914 | | lhs, |
| 1915 | | )) { |
| 1916 | | break :blk lhs_reg; |
| 1917 | | } else { |
| 1918 | | break :blk try self.register_manager.allocReg(inst); |
| 1919 | | } |
| 1920 | | } else try self.register_manager.allocReg(null); |
| 1917 | if (lhs_is_register and self.reuseOperand( |
| 1918 | inst, |
| 1919 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, |
| 1920 | if (lhs_and_rhs_swapped) 1 else 0, |
| 1921 | lhs, |
| 1922 | )) { |
| 1923 | break :blk lhs_reg; |
| 1924 | } else { |
| 1925 | break :blk try self.register_manager.allocReg(inst); |
| 1926 | } |
| 1927 | } else try self.register_manager.allocReg(null), |
| 1928 | }; |
| 1921 | 1929 | |
| 1922 | 1930 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1923 | 1931 | |
| 1924 | 1932 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1925 | 1933 | .add => .add, |
| 1926 | 1934 | .sub => .sub, |
| 1935 | .cmp_eq => .cmp, |
| 1927 | 1936 | .bit_and, |
| 1928 | 1937 | .bool_and, |
| 1929 | 1938 | => .@"and", |
| ... | ... | @@ -1945,6 +1954,7 @@ fn binOpImmediate( |
| 1945 | 1954 | const mir_data: Mir.Inst.Data = switch (tag) { |
| 1946 | 1955 | .add, |
| 1947 | 1956 | .sub, |
| 1957 | .cmp_eq, |
| 1948 | 1958 | .bit_and, |
| 1949 | 1959 | .bool_and, |
| 1950 | 1960 | .bit_or, |
| ... | ... | @@ -1999,6 +2009,7 @@ fn binOp( |
| 1999 | 2009 | switch (tag) { |
| 2000 | 2010 | .add, |
| 2001 | 2011 | .sub, |
| 2012 | .cmp_eq, |
| 2002 | 2013 | => { |
| 2003 | 2014 | switch (lhs_ty.zigTypeTag()) { |
| 2004 | 2015 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| ... | ... | @@ -2012,12 +2023,15 @@ fn binOp( |
| 2012 | 2023 | // operands |
| 2013 | 2024 | const lhs_immediate_ok = switch (tag) { |
| 2014 | 2025 | .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null, |
| 2015 | | .sub => false, |
| 2026 | .sub, |
| 2027 | .cmp_eq, |
| 2028 | => false, |
| 2016 | 2029 | else => unreachable, |
| 2017 | 2030 | }; |
| 2018 | 2031 | const rhs_immediate_ok = switch (tag) { |
| 2019 | 2032 | .add, |
| 2020 | 2033 | .sub, |
| 2034 | .cmp_eq, |
| 2021 | 2035 | => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null, |
| 2022 | 2036 | else => unreachable, |
| 2023 | 2037 | }; |
| ... | ... | @@ -2150,31 +2164,6 @@ fn binOp( |
| 2150 | 2164 | } |
| 2151 | 2165 | } |
| 2152 | 2166 | |
| 2153 | | fn 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 | | |
| 2178 | 2167 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { |
| 2179 | 2168 | switch (abi_size) { |
| 2180 | 2169 | 1, 3, 4 => { |
| ... | ... | @@ -2548,84 +2537,38 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2548 | 2537 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2549 | 2538 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 2550 | 2539 | |
| 2551 | | if (lhs_ty.abiSize(self.target.*) > 4) { |
| 2552 | | return self.fail("TODO cmp for types with size > 4", .{}); |
| 2553 | | } |
| 2554 | | |
| 2555 | | const signedness: std.builtin.Signedness = blk: { |
| 2556 | | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 2557 | | if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned; |
| 2558 | | |
| 2559 | | // incase of an actual integer, we emit the correct signedness |
| 2560 | | break :blk lhs_ty.intInfo(self.target.*).signedness; |
| 2561 | | }; |
| 2562 | | |
| 2563 | | try self.spillCompareFlagsIfOccupied(); |
| 2564 | | self.compare_flags_inst = inst; |
| 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); |
| 2540 | switch (lhs_ty.zigTypeTag()) { |
| 2541 | .Vector => return self.fail("TODO ARM cmp vectors", .{}), |
| 2542 | .Optional => return self.fail("TODO ARM cmp optionals", .{}), |
| 2543 | .Float => return self.fail("TODO ARM cmp floats", .{}), |
| 2544 | .Int, .Bool, .Pointer, .ErrorSet, .Enum => { |
| 2545 | var int_buffer: Type.Payload.Bits = undefined; |
| 2546 | const int_ty = switch (lhs_ty.zigTypeTag()) { |
| 2547 | .Enum => lhs_ty.intTagType(&int_buffer), |
| 2548 | .Int => lhs_ty, |
| 2549 | .Bool => Type.initTag(.u1), |
| 2550 | .Pointer => Type.usize, |
| 2551 | .ErrorSet => Type.initTag(.u16), |
| 2552 | else => unreachable, |
| 2553 | }; |
| 2570 | 2554 | |
| 2571 | | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| 2572 | | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| 2573 | | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); |
| 2574 | | defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register}); |
| 2555 | const int_info = int_ty.intInfo(self.target.*); |
| 2556 | if (int_info.bits <= 32) { |
| 2557 | try self.spillCompareFlagsIfOccupied(); |
| 2558 | self.compare_flags_inst = inst; |
| 2575 | 2559 | |
| 2576 | | var lhs_mcv = lhs; |
| 2577 | | var rhs_mcv = rhs; |
| 2560 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); |
| 2578 | 2561 | |
| 2579 | | // Allocate registers |
| 2580 | | if (rhs_should_be_register) { |
| 2581 | | if (!lhs_is_register and !rhs_is_register) { |
| 2582 | | const regs = try self.register_manager.allocRegs(2, .{ |
| 2583 | | Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, |
| 2584 | | }); |
| 2585 | | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2586 | | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2587 | | } else if (!rhs_is_register) { |
| 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); |
| 2562 | break :result switch (int_info.signedness) { |
| 2563 | .signed => MCValue{ .compare_flags_signed = op }, |
| 2564 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| 2565 | }; |
| 2566 | } else { |
| 2567 | return self.fail("TODO ARM cmp for ints > 32 bits", .{}); |
| 2568 | } |
| 2569 | }, |
| 2570 | else => unreachable, |
| 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 | 2573 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2631 | 2574 | } |