| @@ -1465,7 +1465,6 @@ static int asm_parse_vfp_regvar(int t, int double_precision) · 1464 unmodified lines |
| 1465 | return -1; | 1465 | return -1; |
| 1466 | } | 1466 | } |
| 1467 | | 1467 | |
| 1468 | | | |
| 1469 | static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token) | 1468 | static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token) |
| 1470 | { | 1469 | { |
| 1471 | Operand ops[3]; | 1470 | Operand ops[3]; |
| @@ -1648,6 +1647,264 @@ static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int toke · 176 unmodified lines |
| 1648 | else | 1647 | else |
| 1649 | asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, first_regset_register, &ops[0], &offset, 0, preincrement, op0_exclam, extra_register_bit, load); | 1648 | asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, first_regset_register, &ops[0], &offset, 0, preincrement, op0_exclam, extra_register_bit, load); |
| 1650 | } | 1649 | } |
| | 1650 | |
| | 1651 | // Not standalone. |
| | 1652 | static void asm_floating_point_immediate_data_processing_opcode_tail(TCCState *s1, int token, uint8_t coprocessor, uint8_t CRd) { |
| | 1653 | uint8_t opcode1 = 0; |
| | 1654 | uint8_t opcode2 = 0; |
| | 1655 | uint8_t operands[3] = {0, 0, 0}; |
| | 1656 | Operand operand; |
| | 1657 | |
| | 1658 | operands[0] = CRd; |
| | 1659 | |
| | 1660 | parse_operand(s1, &operand); |
| | 1661 | if (operand.type != OP_IM8 && operand.type != OP_IM8N) { |
| | 1662 | expect("Immediate value"); |
| | 1663 | return; |
| | 1664 | } |
| | 1665 | |
| | 1666 | opcode1 = 11; // "Other" instruction |
| | 1667 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 1668 | case TOK_ASM_vcmpeq_f32: |
| | 1669 | case TOK_ASM_vcmpeq_f64: |
| | 1670 | opcode2 = 2; |
| | 1671 | operands[1] = 5; |
| | 1672 | if (operand.e.v) { |
| | 1673 | expect("Immediate value 0"); |
| | 1674 | return; |
| | 1675 | } |
| | 1676 | break; |
| | 1677 | case TOK_ASM_vcmpeeq_f32: |
| | 1678 | case TOK_ASM_vcmpeeq_f64: |
| | 1679 | opcode2 = 6; |
| | 1680 | operands[1] = 5; |
| | 1681 | if (operand.e.v) { |
| | 1682 | expect("Immediate value 0"); |
| | 1683 | return; |
| | 1684 | } |
| | 1685 | break; |
| | 1686 | default: |
| | 1687 | expect("known floating point with immediate instruction"); |
| | 1688 | return; |
| | 1689 | } |
| | 1690 | |
| | 1691 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { |
| | 1692 | if (operands[0] & 1) |
| | 1693 | opcode1 |= 4; |
| | 1694 | operands[0] >>= 1; |
| | 1695 | } |
| | 1696 | |
| | 1697 | asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, operands[0], operands[1], operands[2], opcode2, 0); |
| | 1698 | } |
| | 1699 | |
| | 1700 | static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { |
| | 1701 | uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| | 1702 | uint8_t opcode1 = 0; |
| | 1703 | uint8_t opcode2 = 0; // (0 || 2) | register selection |
| | 1704 | uint8_t operands[3]; |
| | 1705 | uint8_t nb_operands = 0; |
| | 1706 | int operand_1_register = 1; |
| | 1707 | int reg; |
| | 1708 | |
| | 1709 | /* TODO: |
| | 1710 | Instruction opcode opcode2 Reason |
| | 1711 | ============================================================= |
| | 1712 | - 1?00 ?1? Undefined |
| | 1713 | VFNMS 1?01 ?0? Must be unconditional |
| | 1714 | VFNMA 1?01 ?1? Must be unconditional |
| | 1715 | VFMA 1?10 ?0? Must be unconditional |
| | 1716 | VFMS 1?10 ?1? Must be unconditional |
| | 1717 | |
| | 1718 | VCVT* |
| | 1719 | |
| | 1720 | VMOV Fd, Fm |
| | 1721 | VMOV Sn, Rd |
| | 1722 | VMOV Rd, Sn |
| | 1723 | VMOV Sn, Sm, Rd, Rn |
| | 1724 | VMOV Rd, Rn, Sn, Sm |
| | 1725 | VMOV Dm, Rd, Rn |
| | 1726 | VMOV Rd, Rn, Dm |
| | 1727 | VMOV Dn[0], Rd |
| | 1728 | VMOV Rd, Dn[0] |
| | 1729 | VMOV Dn[1], Rd |
| | 1730 | VMOV Rd, Dn[1] |
| | 1731 | |
| | 1732 | VMSR <sysreg>, Rd |
| | 1733 | VMRS Rd, <sysreg> |
| | 1734 | VMRS APSR_nzcv, FPSCR |
| | 1735 | */ |
| | 1736 | |
| | 1737 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 1738 | case TOK_ASM_vmlaeq_f64: |
| | 1739 | case TOK_ASM_vmlseq_f64: |
| | 1740 | case TOK_ASM_vnmlseq_f64: |
| | 1741 | case TOK_ASM_vnmlaeq_f64: |
| | 1742 | case TOK_ASM_vmuleq_f64: |
| | 1743 | case TOK_ASM_vnmuleq_f64: |
| | 1744 | case TOK_ASM_vaddeq_f64: |
| | 1745 | case TOK_ASM_vsubeq_f64: |
| | 1746 | case TOK_ASM_vdiveq_f64: |
| | 1747 | case TOK_ASM_vnegeq_f64: |
| | 1748 | case TOK_ASM_vabseq_f64: |
| | 1749 | case TOK_ASM_vsqrteq_f64: |
| | 1750 | case TOK_ASM_vcmpeq_f64: |
| | 1751 | case TOK_ASM_vcmpeeq_f64: |
| | 1752 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| | 1753 | } |
| | 1754 | |
| | 1755 | for (nb_operands = 0; nb_operands < 3; ) { |
| | 1756 | if (nb_operands == 1 && (tok == '#' || tok == '$')) { |
| | 1757 | asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, operands[0]); |
| | 1758 | return; |
| | 1759 | } |
| | 1760 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { |
| | 1761 | if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { |
| | 1762 | operands[nb_operands] = reg; |
| | 1763 | next(); |
| | 1764 | } else { |
| | 1765 | expect("'s<number>'"); |
| | 1766 | return; |
| | 1767 | } |
| | 1768 | } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) { |
| | 1769 | if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { |
| | 1770 | operands[nb_operands] = reg; |
| | 1771 | next(); |
| | 1772 | } else { |
| | 1773 | expect("'d<number>'"); |
| | 1774 | return; |
| | 1775 | } |
| | 1776 | } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { |
| | 1777 | coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| | 1778 | operands[nb_operands] = reg; |
| | 1779 | next(); |
| | 1780 | } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { |
| | 1781 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| | 1782 | operands[nb_operands] = reg; |
| | 1783 | next(); |
| | 1784 | } else |
| | 1785 | tcc_internal_error("unknown coprocessor"); |
| | 1786 | ++nb_operands; |
| | 1787 | if (tok == ',') |
| | 1788 | next(); |
| | 1789 | else |
| | 1790 | break; |
| | 1791 | } |
| | 1792 | |
| | 1793 | if (nb_operands == 2) { // implicit |
| | 1794 | operands[2] = operands[1]; |
| | 1795 | operands[1] = operands[0]; |
| | 1796 | nb_operands = 3; |
| | 1797 | } |
| | 1798 | if (nb_operands < 3) { |
| | 1799 | tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_operands); |
| | 1800 | return; |
| | 1801 | } |
| | 1802 | |
| | 1803 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 1804 | case TOK_ASM_vmlaeq_f32: |
| | 1805 | case TOK_ASM_vmlaeq_f64: |
| | 1806 | opcode1 = 0; |
| | 1807 | opcode2 = 0; |
| | 1808 | break; |
| | 1809 | case TOK_ASM_vmlseq_f32: |
| | 1810 | case TOK_ASM_vmlseq_f64: |
| | 1811 | opcode1 = 0; |
| | 1812 | opcode2 = 2; |
| | 1813 | break; |
| | 1814 | case TOK_ASM_vnmlseq_f32: |
| | 1815 | case TOK_ASM_vnmlseq_f64: |
| | 1816 | opcode1 = 1; |
| | 1817 | opcode2 = 0; |
| | 1818 | break; |
| | 1819 | case TOK_ASM_vnmlaeq_f32: |
| | 1820 | case TOK_ASM_vnmlaeq_f64: |
| | 1821 | opcode1 = 1; |
| | 1822 | opcode2 = 2; |
| | 1823 | break; |
| | 1824 | case TOK_ASM_vmuleq_f32: |
| | 1825 | case TOK_ASM_vmuleq_f64: |
| | 1826 | opcode1 = 2; |
| | 1827 | opcode2 = 0; |
| | 1828 | break; |
| | 1829 | case TOK_ASM_vnmuleq_f32: |
| | 1830 | case TOK_ASM_vnmuleq_f64: |
| | 1831 | opcode1 = 2; |
| | 1832 | opcode2 = 2; |
| | 1833 | break; |
| | 1834 | case TOK_ASM_vaddeq_f32: |
| | 1835 | case TOK_ASM_vaddeq_f64: |
| | 1836 | opcode1 = 3; |
| | 1837 | opcode2 = 0; |
| | 1838 | break; |
| | 1839 | case TOK_ASM_vsubeq_f32: |
| | 1840 | case TOK_ASM_vsubeq_f64: |
| | 1841 | opcode1 = 3; |
| | 1842 | opcode2 = 2; |
| | 1843 | break; |
| | 1844 | case TOK_ASM_vdiveq_f32: |
| | 1845 | case TOK_ASM_vdiveq_f64: |
| | 1846 | opcode1 = 8; |
| | 1847 | opcode2 = 0; |
| | 1848 | break; |
| | 1849 | case TOK_ASM_vnegeq_f32: |
| | 1850 | case TOK_ASM_vnegeq_f64: |
| | 1851 | opcode1 = 11; // Other" instruction |
| | 1852 | opcode2 = 2; |
| | 1853 | operands[1] = 1; |
| | 1854 | operand_1_register = 0; |
| | 1855 | break; |
| | 1856 | case TOK_ASM_vabseq_f32: |
| | 1857 | case TOK_ASM_vabseq_f64: |
| | 1858 | opcode1 = 11; // "Other" instruction |
| | 1859 | opcode2 = 6; |
| | 1860 | operands[1] = 0; |
| | 1861 | operand_1_register = 0; |
| | 1862 | break; |
| | 1863 | case TOK_ASM_vsqrteq_f32: |
| | 1864 | case TOK_ASM_vsqrteq_f64: |
| | 1865 | opcode1 = 11; // "Other" instruction |
| | 1866 | opcode2 = 6; |
| | 1867 | operands[1] = 1; |
| | 1868 | operand_1_register = 0; |
| | 1869 | break; |
| | 1870 | case TOK_ASM_vcmpeq_f32: |
| | 1871 | case TOK_ASM_vcmpeq_f64: |
| | 1872 | opcode1 = 11; // "Other" instruction |
| | 1873 | opcode2 = 2; |
| | 1874 | operands[1] = 4; |
| | 1875 | operand_1_register = 0; |
| | 1876 | break; |
| | 1877 | case TOK_ASM_vcmpeeq_f32: |
| | 1878 | case TOK_ASM_vcmpeeq_f64: |
| | 1879 | opcode1 = 11; // "Other" instruction |
| | 1880 | opcode2 = 6; |
| | 1881 | operands[1] = 4; |
| | 1882 | operand_1_register = 0; |
| | 1883 | break; |
| | 1884 | // TODO: vcvt; vcvtr |
| | 1885 | default: |
| | 1886 | expect("known floating point instruction"); |
| | 1887 | return; |
| | 1888 | } |
| | 1889 | |
| | 1890 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { |
| | 1891 | if (operands[2] & 1) |
| | 1892 | opcode2 |= 1; |
| | 1893 | operands[2] >>= 1; |
| | 1894 | |
| | 1895 | if (operand_1_register) { |
| | 1896 | if (operands[1] & 1) |
| | 1897 | opcode2 |= 4; |
| | 1898 | operands[1] >>= 1; |
| | 1899 | } |
| | 1900 | |
| | 1901 | if (operands[0] & 1) |
| | 1902 | opcode1 |= 4; |
| | 1903 | operands[0] >>= 1; |
| | 1904 | } |
| | 1905 | |
| | 1906 | asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, operands[0], operands[1], operands[2], opcode2, 0); |
| | 1907 | } |
| 1651 | #endif | 1908 | #endif |
| 1652 | | 1909 | |
| 1653 | static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) | 1910 | static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) |
| @@ -2013,6 +2270,37 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 359 unmodified lines |
| 2013 | asm_floating_point_single_data_transfer_opcode(s1, token); | 2270 | asm_floating_point_single_data_transfer_opcode(s1, token); |
| 2014 | return; | 2271 | return; |
| 2015 | | 2272 | |
| | 2273 | case TOK_ASM_vmlaeq_f32: |
| | 2274 | case TOK_ASM_vmlseq_f32: |
| | 2275 | case TOK_ASM_vnmlseq_f32: |
| | 2276 | case TOK_ASM_vnmlaeq_f32: |
| | 2277 | case TOK_ASM_vmuleq_f32: |
| | 2278 | case TOK_ASM_vnmuleq_f32: |
| | 2279 | case TOK_ASM_vaddeq_f32: |
| | 2280 | case TOK_ASM_vsubeq_f32: |
| | 2281 | case TOK_ASM_vdiveq_f32: |
| | 2282 | case TOK_ASM_vnegeq_f32: |
| | 2283 | case TOK_ASM_vabseq_f32: |
| | 2284 | case TOK_ASM_vsqrteq_f32: |
| | 2285 | case TOK_ASM_vcmpeq_f32: |
| | 2286 | case TOK_ASM_vcmpeeq_f32: |
| | 2287 | case TOK_ASM_vmlaeq_f64: |
| | 2288 | case TOK_ASM_vmlseq_f64: |
| | 2289 | case TOK_ASM_vnmlseq_f64: |
| | 2290 | case TOK_ASM_vnmlaeq_f64: |
| | 2291 | case TOK_ASM_vmuleq_f64: |
| | 2292 | case TOK_ASM_vnmuleq_f64: |
| | 2293 | case TOK_ASM_vaddeq_f64: |
| | 2294 | case TOK_ASM_vsubeq_f64: |
| | 2295 | case TOK_ASM_vdiveq_f64: |
| | 2296 | case TOK_ASM_vnegeq_f64: |
| | 2297 | case TOK_ASM_vabseq_f64: |
| | 2298 | case TOK_ASM_vsqrteq_f64: |
| | 2299 | case TOK_ASM_vcmpeq_f64: |
| | 2300 | case TOK_ASM_vcmpeeq_f64: |
| | 2301 | asm_floating_point_data_processing_opcode(s1, token); |
| | 2302 | return; |
| | 2303 | |
| 2016 | case TOK_ASM_vpusheq: | 2304 | case TOK_ASM_vpusheq: |
| 2017 | case TOK_ASM_vpopeq: | 2305 | case TOK_ASM_vpopeq: |
| 2018 | case TOK_ASM_vldmeq: | 2306 | case TOK_ASM_vldmeq: |