|
1 | 1 | //! Lower a single Cranelift instruction into vcode. |
2 | 2 |
|
3 | 3 | use crate::binemit::CodeOffset; |
4 | | -use crate::ir::condcodes::FloatCC; |
| 4 | +use crate::ir::condcodes::{FloatCC, IntCC}; |
5 | 5 | use crate::ir::types::*; |
6 | 6 | use crate::ir::Inst as IRInst; |
7 | 7 | use crate::ir::{InstructionData, Opcode, TrapCode}; |
@@ -1735,14 +1735,112 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>( |
1735 | 1735 | (false, true) => NarrowValueMode::SignExtend64, |
1736 | 1736 | (false, false) => NarrowValueMode::ZeroExtend64, |
1737 | 1737 | }; |
1738 | | - let rn = put_input_in_reg(ctx, inputs[0], narrow_mode); |
1739 | 1738 |
|
1740 | | - if !ty.is_vector() { |
| 1739 | + if ty == I128 { |
| 1740 | + let lhs = put_input_in_regs(ctx, inputs[0]); |
| 1741 | + let rhs = put_input_in_regs(ctx, inputs[1]); |
| 1742 | + |
| 1743 | + let tmp1 = ctx.alloc_tmp(I64).only_reg().unwrap(); |
| 1744 | + let tmp2 = ctx.alloc_tmp(I64).only_reg().unwrap(); |
| 1745 | + |
| 1746 | + match condcode { |
| 1747 | + IntCC::Equal | IntCC::NotEqual => { |
| 1748 | + // eor tmp1, lhs_lo, rhs_lo |
| 1749 | + // eor tmp2, lhs_hi, rhs_hi |
| 1750 | + // adds xzr, tmp1, tmp2 |
| 1751 | + // cset dst, {eq, ne} |
| 1752 | + |
| 1753 | + ctx.emit(Inst::AluRRR { |
| 1754 | + alu_op: ALUOp::Eor64, |
| 1755 | + rd: tmp1, |
| 1756 | + rn: lhs.regs()[0], |
| 1757 | + rm: rhs.regs()[0], |
| 1758 | + }); |
| 1759 | + ctx.emit(Inst::AluRRR { |
| 1760 | + alu_op: ALUOp::Eor64, |
| 1761 | + rd: tmp2, |
| 1762 | + rn: lhs.regs()[1], |
| 1763 | + rm: rhs.regs()[1], |
| 1764 | + }); |
| 1765 | + ctx.emit(Inst::AluRRR { |
| 1766 | + alu_op: ALUOp::AddS64, |
| 1767 | + rd: writable_zero_reg(), |
| 1768 | + rn: tmp1.to_reg(), |
| 1769 | + rm: tmp2.to_reg(), |
| 1770 | + }); |
| 1771 | + materialize_bool_result(ctx, insn, rd, cond); |
| 1772 | + } |
| 1773 | + IntCC::Overflow | IntCC::NotOverflow => { |
| 1774 | + // We can do an 128bit add while throwing away the results |
| 1775 | + // and check the overflow flags at the end. |
| 1776 | + // |
| 1777 | + // adds xzr, lhs_lo, rhs_lo |
| 1778 | + // adcs xzr, lhs_hi, rhs_hi |
| 1779 | + // cset dst, {vs, vc} |
| 1780 | + |
| 1781 | + ctx.emit(Inst::AluRRR { |
| 1782 | + alu_op: ALUOp::AddS64, |
| 1783 | + rd: writable_zero_reg(), |
| 1784 | + rn: lhs.regs()[0], |
| 1785 | + rm: rhs.regs()[0], |
| 1786 | + }); |
| 1787 | + ctx.emit(Inst::AluRRR { |
| 1788 | + alu_op: ALUOp::AdcS64, |
| 1789 | + rd: writable_zero_reg(), |
| 1790 | + rn: lhs.regs()[1], |
| 1791 | + rm: rhs.regs()[1], |
| 1792 | + }); |
| 1793 | + materialize_bool_result(ctx, insn, rd, cond); |
| 1794 | + } |
| 1795 | + _ => { |
| 1796 | + // cmp lhs_lo, rhs_lo |
| 1797 | + // cset tmp1, low_cc |
| 1798 | + // cmp lhs_hi, rhs_hi |
| 1799 | + // cset tmp2, cond |
| 1800 | + // csel dst, tmp1, tmp2, eq |
| 1801 | + |
| 1802 | + let low_cc = match condcode { |
| 1803 | + IntCC::SignedGreaterThanOrEqual | IntCC::UnsignedGreaterThanOrEqual => { |
| 1804 | + Cond::Hs |
| 1805 | + } |
| 1806 | + IntCC::SignedGreaterThan | IntCC::UnsignedGreaterThan => Cond::Hi, |
| 1807 | + IntCC::SignedLessThanOrEqual | IntCC::UnsignedLessThanOrEqual => { |
| 1808 | + Cond::Ls |
| 1809 | + } |
| 1810 | + IntCC::SignedLessThan | IntCC::UnsignedLessThan => Cond::Lo, |
| 1811 | + _ => unreachable!(), |
| 1812 | + }; |
| 1813 | + |
| 1814 | + ctx.emit(Inst::AluRRR { |
| 1815 | + alu_op: ALUOp::SubS64, |
| 1816 | + rd: writable_zero_reg(), |
| 1817 | + rn: lhs.regs()[0], |
| 1818 | + rm: rhs.regs()[0], |
| 1819 | + }); |
| 1820 | + materialize_bool_result(ctx, insn, tmp1, low_cc); |
| 1821 | + ctx.emit(Inst::AluRRR { |
| 1822 | + alu_op: ALUOp::SubS64, |
| 1823 | + rd: writable_zero_reg(), |
| 1824 | + rn: lhs.regs()[1], |
| 1825 | + rm: rhs.regs()[1], |
| 1826 | + }); |
| 1827 | + materialize_bool_result(ctx, insn, tmp2, cond); |
| 1828 | + ctx.emit(Inst::CSel { |
| 1829 | + cond: Cond::Eq, |
| 1830 | + rd, |
| 1831 | + rn: tmp1.to_reg(), |
| 1832 | + rm: tmp2.to_reg(), |
| 1833 | + }); |
| 1834 | + } |
| 1835 | + } |
| 1836 | + } else if !ty.is_vector() { |
1741 | 1837 | let alu_op = choose_32_64(ty, ALUOp::SubS32, ALUOp::SubS64); |
| 1838 | + let rn = put_input_in_reg(ctx, inputs[0], narrow_mode); |
1742 | 1839 | let rm = put_input_in_rse_imm12(ctx, inputs[1], narrow_mode); |
1743 | 1840 | ctx.emit(alu_inst_imm12(alu_op, writable_zero_reg(), rn, rm)); |
1744 | 1841 | materialize_bool_result(ctx, insn, rd, cond); |
1745 | 1842 | } else { |
| 1843 | + let rn = put_input_in_reg(ctx, inputs[0], narrow_mode); |
1746 | 1844 | let rm = put_input_in_reg(ctx, inputs[1], narrow_mode); |
1747 | 1845 | lower_vector_compare(ctx, rd, rn, rm, ty, cond)?; |
1748 | 1846 | } |
|
0 commit comments