Unified · Split
| @@ -41,9 +41,13 @@ enum { · 40 unmodified lines | ||
| 41 | 41 | OPT_IM8, |
| 42 | 42 | OPT_IM8N, |
| 43 | 43 | OPT_IM32, |
| 44 | + OPT_VREG32, | |
| 45 | + OPT_VREG64, | |
| 44 | 46 | }; |
| 45 | 47 | #define OP_REG32 (1 << OPT_REG32) |
| 46 | −#define OP_REG (OP_REG32) | |
| 48 | +#define OP_VREG32 (1 << OPT_VREG32) | |
| 49 | +#define OP_VREG64 (1 << OPT_VREG64) | |
| 50 | +#define OP_REG (OP_REG32 | OP_VREG32 | OP_VREG64) | |
| 47 | 51 | #define OP_IM32 (1 << OPT_IM32) |
| 48 | 52 | #define OP_IM8 (1 << OPT_IM8) |
| 49 | 53 | #define OP_IM8N (1 << OPT_IM8N) |
| @@ -58,6 +62,21 @@ typedef struct Operand { · 8 unmodified lines | ||
| 58 | 62 | }; |
| 59 | 63 | } Operand; |
| 60 | 64 | |
| 65 | +/* Read the VFP register referred to by token T. | |
| 66 | + If OK, returns its number. | |
| 67 | + If not OK, returns -1. */ | |
| 68 | +static int asm_parse_vfp_regvar(int t, int double_precision) | |
| 69 | +{ | |
| 70 | + if (double_precision) { | |
| 71 | + if (t >= TOK_ASM_d0 && t <= TOK_ASM_d15) | |
| 72 | + return t - TOK_ASM_d0; | |
| 73 | + } else { | |
| 74 | + if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31) | |
| 75 | + return t - TOK_ASM_s0; | |
| 76 | + } | |
| 77 | + return -1; | |
| 78 | +} | |
| 79 | + | |
| 61 | 80 | /* Parse a text containing operand and store the result in OP */ |
| 62 | 81 | static void parse_operand(TCCState *s1, Operand *op) |
| 63 | 82 | { |
| @@ -111,6 +130,14 @@ static void parse_operand(TCCState *s1, Operand *op) · 47 unmodified lines | ||
| 111 | 130 | next(); // skip register name |
| 112 | 131 | op->type = OP_REG32; |
| 113 | 132 | op->reg = (uint8_t) reg; |
| 133 | + } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | |
| 134 | + next(); // skip register name | |
| 135 | + op->type = OP_VREG32; | |
| 136 | + op->reg = (uint8_t) reg; | |
| 137 | + } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | |
| 138 | + next(); // skip register name | |
| 139 | + op->type = OP_VREG64; | |
| 140 | + op->reg = (uint8_t) reg; | |
| 114 | 141 | } else |
| 115 | 142 | expect("operand"); |
| 116 | 143 | } |
| @@ -1450,41 +1477,25 @@ static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token) · 1333 unmodified lines | ||
| 1450 | 1477 | #define CP_SINGLE_PRECISION_FLOAT 10 |
| 1451 | 1478 | #define CP_DOUBLE_PRECISION_FLOAT 11 |
| 1452 | 1479 | |
| 1453 | −/* Read the VFP register referred to by T. | |
| 1454 | − If OK, returns its number. | |
| 1455 | − If not OK, returns -1. */ | |
| 1456 | −static int asm_parse_vfp_regvar(int t, int double_precision) | |
| 1457 | −{ | |
| 1458 | − if (double_precision) { | |
| 1459 | − if (t >= TOK_ASM_d0 && t <= TOK_ASM_d15) | |
| 1460 | − return t - TOK_ASM_d0; | |
| 1461 | − } else { | |
| 1462 | − if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31) | |
| 1463 | − return t - TOK_ASM_s0; | |
| 1464 | − } | |
| 1465 | − return -1; | |
| 1466 | −} | |
| 1467 | − | |
| 1468 | 1480 | static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token) |
| 1469 | 1481 | { |
| 1470 | 1482 | Operand ops[3]; |
| 1471 | 1483 | uint8_t coprocessor = 0; |
| 1472 | 1484 | uint8_t coprocessor_destination_register = 0; |
| 1473 | 1485 | int long_transfer = 0; |
| 1474 | − int reg; | |
| 1475 | 1486 | // Note: vldr p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged |
| 1476 | 1487 | // Note: Not allowed: vldr p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4 |
| 1477 | 1488 | // Note: Not allowed: vldr p3, c0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4 |
| 1478 | 1489 | |
| 1479 | − if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | |
| 1490 | + parse_operand(s1, &ops[0]); | |
| 1491 | + if (ops[0].type == OP_VREG32) { | |
| 1480 | 1492 | coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| 1481 | − coprocessor_destination_register = reg; | |
| 1493 | + coprocessor_destination_register = ops[0].reg; | |
| 1482 | 1494 | long_transfer = coprocessor_destination_register & 1; |
| 1483 | 1495 | coprocessor_destination_register >>= 1; |
| 1484 | − next(); | |
| 1485 | − } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | |
| 1496 | + } else if (ops[0].type == OP_VREG64) { | |
| 1486 | 1497 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| 1487 | − coprocessor_destination_register = reg; | |
| 1498 | + coprocessor_destination_register = ops[0].reg; | |
| 1488 | 1499 | next(); |
| 1489 | 1500 | } else { |
| 1490 | 1501 | expect("floating point register"); |
| @@ -1809,10 +1820,8 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { · 318 unmodified lines | ||
| 1809 | 1820 | uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| 1810 | 1821 | uint8_t opcode1 = 0; |
| 1811 | 1822 | uint8_t opcode2 = 0; // (0 || 2) | register selection |
| 1812 | − uint8_t operands[3]; | |
| 1813 | − uint8_t nb_operands = 0; | |
| 1814 | − int operand_1_register = 1; | |
| 1815 | − int reg; | |
| 1823 | + Operand ops[3]; | |
| 1824 | + uint8_t nb_ops = 0; | |
| 1816 | 1825 | |
| 1817 | 1826 | /* TODO: |
| 1818 | 1827 | Instruction opcode opcode2 Reason |
| @@ -1861,51 +1870,40 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { · 42 unmodified lines | ||
| 1861 | 1870 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| 1862 | 1871 | } |
| 1863 | 1872 | |
| 1864 | − for (nb_operands = 0; nb_operands < 3; ) { | |
| 1865 | − if (nb_operands == 1 && (tok == '#' || tok == '$')) { | |
| 1866 | − asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, operands[0]); | |
| 1873 | + for (nb_ops = 0; nb_ops < 3; ) { | |
| 1874 | + if (nb_ops == 1 && (tok == '#' || tok == '$')) { | |
| 1875 | + asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, ops[0].reg); | |
| 1867 | 1876 | return; |
| 1868 | 1877 | } |
| 1869 | − if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { | |
| 1870 | − if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | |
| 1871 | − operands[nb_operands] = reg; | |
| 1872 | − next(); | |
| 1873 | − } else { | |
| 1878 | + parse_operand(s1, &ops[nb_ops]); | |
| 1879 | + if (ops[nb_ops].type == OP_VREG32) { | |
| 1880 | + if (coprocessor != CP_SINGLE_PRECISION_FLOAT) { | |
| 1874 | 1881 | expect("'s<number>'"); |
| 1875 | 1882 | return; |
| 1876 | 1883 | } |
| 1877 | − } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) { | |
| 1878 | − if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | |
| 1879 | − operands[nb_operands] = reg; | |
| 1880 | − next(); | |
| 1881 | − } else { | |
| 1884 | + } else if (ops[nb_ops].type == OP_VREG64) { | |
| 1885 | + if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) { | |
| 1882 | 1886 | expect("'d<number>'"); |
| 1883 | 1887 | return; |
| 1884 | 1888 | } |
| 1885 | − } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | |
| 1886 | − coprocessor = CP_SINGLE_PRECISION_FLOAT; | |
| 1887 | − operands[nb_operands] = reg; | |
| 1888 | − next(); | |
| 1889 | − } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | |
| 1890 | − coprocessor = CP_DOUBLE_PRECISION_FLOAT; | |
| 1891 | − operands[nb_operands] = reg; | |
| 1892 | − next(); | |
| 1893 | − } else | |
| 1894 | − tcc_internal_error("unknown coprocessor"); | |
| 1895 | − ++nb_operands; | |
| 1889 | + } else { | |
| 1890 | + expect("floating point register"); | |
| 1891 | + return; | |
| 1892 | + } | |
| 1893 | + ++nb_ops; | |
| 1896 | 1894 | if (tok == ',') |
| 1897 | 1895 | next(); |
| 1898 | 1896 | else |
| 1899 | 1897 | break; |
| 1900 | 1898 | } |
| 1901 | 1899 | |
| 1902 | − if (nb_operands == 2) { // implicit | |
| 1903 | − operands[2] = operands[1]; | |
| 1904 | − operands[1] = operands[0]; | |
| 1905 | − nb_operands = 3; | |
| 1900 | + if (nb_ops == 2) { // implicit | |
| 1901 | + memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2] | |
| 1902 | + memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit | |
| 1903 | + nb_ops = 3; | |
| 1906 | 1904 | } |
| 1907 | − if (nb_operands < 3) { | |
| 1908 | − tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_operands); | |
| 1905 | + if (nb_ops < 3) { | |
| 1906 | + tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_ops); | |
| 1909 | 1907 | return; |
| 1910 | 1908 | } |
| 1911 | 1909 | |
| @@ -1959,43 +1957,44 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { · 47 unmodified lines | ||
| 1959 | 1957 | case TOK_ASM_vnegeq_f64: |
| 1960 | 1958 | opcode1 = 11; // Other" instruction |
| 1961 | 1959 | opcode2 = 2; |
| 1962 | − operands[1] = 1; | |
| 1963 | − operand_1_register = 0; | |
| 1960 | + ops[1].type = OP_IM8; | |
| 1961 | + ops[1].e.v = 1; | |
| 1964 | 1962 | break; |
| 1965 | 1963 | case TOK_ASM_vabseq_f32: |
| 1966 | 1964 | case TOK_ASM_vabseq_f64: |
| 1967 | 1965 | opcode1 = 11; // "Other" instruction |
| 1968 | 1966 | opcode2 = 6; |
| 1969 | − operands[1] = 0; | |
| 1970 | − operand_1_register = 0; | |
| 1967 | + ops[1].type = OP_IM8; | |
| 1968 | + ops[1].e.v = 0; | |
| 1971 | 1969 | break; |
| 1972 | 1970 | case TOK_ASM_vsqrteq_f32: |
| 1973 | 1971 | case TOK_ASM_vsqrteq_f64: |
| 1974 | 1972 | opcode1 = 11; // "Other" instruction |
| 1975 | 1973 | opcode2 = 6; |
| 1976 | − operands[1] = 1; | |
| 1977 | − operand_1_register = 0; | |
| 1974 | + ops[1].type = OP_IM8; | |
| 1975 | + ops[1].e.v = 1; | |
| 1978 | 1976 | break; |
| 1979 | 1977 | case TOK_ASM_vcmpeq_f32: |
| 1980 | 1978 | case TOK_ASM_vcmpeq_f64: |
| 1981 | 1979 | opcode1 = 11; // "Other" instruction |
| 1982 | 1980 | opcode2 = 2; |
| 1983 | − operands[1] = 4; | |
| 1984 | − operand_1_register = 0; | |
| 1981 | + ops[1].type = OP_IM8; | |
| 1982 | + ops[1].e.v = 4; | |
| 1985 | 1983 | break; |
| 1986 | 1984 | case TOK_ASM_vcmpeeq_f32: |
| 1987 | 1985 | case TOK_ASM_vcmpeeq_f64: |
| 1988 | 1986 | opcode1 = 11; // "Other" instruction |
| 1989 | 1987 | opcode2 = 6; |
| 1990 | − operands[1] = 4; | |
| 1991 | − operand_1_register = 0; | |
| 1988 | + ops[1].type = OP_IM8; | |
| 1989 | + ops[1].e.v = 4; | |
| 1992 | 1990 | break; |
| 1993 | 1991 | case TOK_ASM_vmoveq_f32: |
| 1994 | 1992 | case TOK_ASM_vmoveq_f64: |
| 1993 | + // FIXME: Check for ARM registers--and allow only very little. | |
| 1995 | 1994 | opcode1 = 11; // "Other" instruction |
| 1996 | 1995 | opcode2 = 2; |
| 1997 | − operands[1] = 0; | |
| 1998 | − operand_1_register = 0; | |
| 1996 | + ops[1].type = OP_IM8; | |
| 1997 | + ops[1].e.v = 0; | |
| 1999 | 1998 | break; |
| 2000 | 1999 | // TODO: vcvt; vcvtr |
| 2001 | 2000 | default: |
| @@ -2004,22 +2003,26 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { · 2 unmodified lines | ||
| 2004 | 2003 | } |
| 2005 | 2004 | |
| 2006 | 2005 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { |
| 2007 | − if (operands[2] & 1) | |
| 2008 | − opcode2 |= 1; | |
| 2009 | − operands[2] >>= 1; | |
| 2006 | + if (ops[2].type == OP_VREG32) { | |
| 2007 | + if (ops[2].reg & 1) | |
| 2008 | + opcode2 |= 1; | |
| 2009 | + ops[2].reg >>= 1; | |
| 2010 | + } | |
| 2010 | 2011 | |
| 2011 | − if (operand_1_register) { | |
| 2012 | − if (operands[1] & 1) | |
| 2012 | + if (ops[1].type == OP_VREG32) { | |
| 2013 | + if (ops[1].reg & 1) | |
| 2013 | 2014 | opcode2 |= 4; |
| 2014 | − operands[1] >>= 1; | |
| 2015 | + ops[1].reg >>= 1; | |
| 2015 | 2016 | } |
| 2016 | 2017 | |
| 2017 | − if (operands[0] & 1) | |
| 2018 | − opcode1 |= 4; | |
| 2019 | − operands[0] >>= 1; | |
| 2018 | + if (ops[0].type == OP_VREG32) { | |
| 2019 | + if (ops[0].reg & 1) | |
| 2020 | + opcode1 |= 4; | |
| 2021 | + ops[0].reg >>= 1; | |
| 2022 | + } | |
| 2020 | 2023 | } |
| 2021 | 2024 | |
| 2022 | − asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, operands[0], operands[1], operands[2], opcode2, 0); | |
| 2025 | + asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, (ops[2].type == OP_IM8) ? ops[2].e.v : ops[2].reg, opcode2, 0); | |
| 2023 | 2026 | } |
| 2024 | 2027 | #endif |
| 2025 | 2028 | |