Unified · Split
| @@ -41,9 +41,13 @@ enum { · 40 unmodified lines | |||
| 41 | OPT_IM8, | 41 | OPT_IM8, |
| 42 | OPT_IM8N, | 42 | OPT_IM8N, |
| 43 | OPT_IM32, | 43 | OPT_IM32, |
| 44 | OPT_VREG32, | ||
| 45 | OPT_VREG64, | ||
| 44 | }; | 46 | }; |
| 45 | #define OP_REG32 (1 << OPT_REG32) | 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 | #define OP_IM32 (1 << OPT_IM32) | 51 | #define OP_IM32 (1 << OPT_IM32) |
| 48 | #define OP_IM8 (1 << OPT_IM8) | 52 | #define OP_IM8 (1 << OPT_IM8) |
| 49 | #define OP_IM8N (1 << OPT_IM8N) | 53 | #define OP_IM8N (1 << OPT_IM8N) |
| @@ -58,6 +62,21 @@ typedef struct Operand { · 8 unmodified lines | |||
| 58 | }; | 62 | }; |
| 59 | } Operand; | 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 | /* Parse a text containing operand and store the result in OP */ | 80 | /* Parse a text containing operand and store the result in OP */ |
| 62 | static void parse_operand(TCCState *s1, Operand *op) | 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 | next(); // skip register name | 130 | next(); // skip register name |
| 112 | op->type = OP_REG32; | 131 | op->type = OP_REG32; |
| 113 | op->reg = (uint8_t) reg; | 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 | } else | 141 | } else |
| 115 | expect("operand"); | 142 | expect("operand"); |
| 116 | } | 143 | } |
| @@ -1450,41 +1477,25 @@ static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token) · 1333 unmodified lines | |||
| 1450 | #define CP_SINGLE_PRECISION_FLOAT 10 | 1477 | #define CP_SINGLE_PRECISION_FLOAT 10 |
| 1451 | #define CP_DOUBLE_PRECISION_FLOAT 11 | 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 | static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token) | 1480 | static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token) |
| 1469 | { | 1481 | { |
| 1470 | Operand ops[3]; | 1482 | Operand ops[3]; |
| 1471 | uint8_t coprocessor = 0; | 1483 | uint8_t coprocessor = 0; |
| 1472 | uint8_t coprocessor_destination_register = 0; | 1484 | uint8_t coprocessor_destination_register = 0; |
| 1473 | int long_transfer = 0; | 1485 | int long_transfer = 0; |
| 1474 | int reg; | ||
| 1475 | // Note: vldr p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged | 1486 | // Note: vldr p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged |
| 1476 | // Note: Not allowed: vldr p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4 | 1487 | // Note: Not allowed: vldr p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4 |
| 1477 | // Note: Not allowed: vldr p3, c0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4 | 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 | coprocessor = CP_SINGLE_PRECISION_FLOAT; | 1492 | coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| 1481 | coprocessor_destination_register = reg; | 1493 | coprocessor_destination_register = ops[0].reg; |
| 1482 | long_transfer = coprocessor_destination_register & 1; | 1494 | long_transfer = coprocessor_destination_register & 1; |
| 1483 | coprocessor_destination_register >>= 1; | 1495 | coprocessor_destination_register >>= 1; |
| 1484 | next(); | 1496 | } else if (ops[0].type == OP_VREG64) { |
| 1485 | } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | ||
| 1486 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; | 1497 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| 1487 | coprocessor_destination_register = reg; | 1498 | coprocessor_destination_register = ops[0].reg; |
| 1488 | next(); | 1499 | next(); |
| 1489 | } else { | 1500 | } else { |
| 1490 | expect("floating point register"); | 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 | uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; | 1820 | uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; |
| 1810 | uint8_t opcode1 = 0; | 1821 | uint8_t opcode1 = 0; |
| 1811 | uint8_t opcode2 = 0; // (0 || 2) | register selection | 1822 | uint8_t opcode2 = 0; // (0 || 2) | register selection |
| 1812 | uint8_t operands[3]; | 1823 | Operand ops[3]; |
| 1813 | uint8_t nb_operands = 0; | 1824 | uint8_t nb_ops = 0; |
| 1814 | int operand_1_register = 1; | ||
| 1815 | int reg; | ||
| 1816 | 1825 | ||
| 1817 | /* TODO: | 1826 | /* TODO: |
| 1818 | Instruction opcode opcode2 Reason | 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 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; | 1870 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; |
| 1862 | } | 1871 | } |
| 1863 | 1872 | ||
| 1864 | for (nb_operands = 0; nb_operands < 3; ) { | 1873 | for (nb_ops = 0; nb_ops < 3; ) { |
| 1865 | if (nb_operands == 1 && (tok == '#' || tok == '$')) { | 1874 | if (nb_ops == 1 && (tok == '#' || tok == '$')) { |
| 1866 | asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, operands[0]); | 1875 | asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, ops[0].reg); |
| 1867 | return; | 1876 | return; |
| 1868 | } | 1877 | } |
| 1869 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { | 1878 | parse_operand(s1, &ops[nb_ops]); |
| 1870 | if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | 1879 | if (ops[nb_ops].type == OP_VREG32) { |
| 1871 | operands[nb_operands] = reg; | 1880 | if (coprocessor != CP_SINGLE_PRECISION_FLOAT) { |
| 1872 | next(); | ||
| 1873 | } else { | ||
| 1874 | expect("'s<number>'"); | 1881 | expect("'s<number>'"); |
| 1875 | return; | 1882 | return; |
| 1876 | } | 1883 | } |
| 1877 | } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) { | 1884 | } else if (ops[nb_ops].type == OP_VREG64) { |
| 1878 | if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | 1885 | if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) { |
| 1879 | operands[nb_operands] = reg; | ||
| 1880 | next(); | ||
| 1881 | } else { | ||
| 1882 | expect("'d<number>'"); | 1886 | expect("'d<number>'"); |
| 1883 | return; | 1887 | return; |
| 1884 | } | 1888 | } |
| 1885 | } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) { | 1889 | } else { |
| 1886 | coprocessor = CP_SINGLE_PRECISION_FLOAT; | 1890 | expect("floating point register"); |
| 1887 | operands[nb_operands] = reg; | 1891 | return; |
| 1888 | next(); | 1892 | } |
| 1889 | } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) { | 1893 | ++nb_ops; |
| 1890 | coprocessor = CP_DOUBLE_PRECISION_FLOAT; | ||
| 1891 | operands[nb_operands] = reg; | ||
| 1892 | next(); | ||
| 1893 | } else | ||
| 1894 | tcc_internal_error("unknown coprocessor"); | ||
| 1895 | ++nb_operands; | ||
| 1896 | if (tok == ',') | 1894 | if (tok == ',') |
| 1897 | next(); | 1895 | next(); |
| 1898 | else | 1896 | else |
| 1899 | break; | 1897 | break; |
| 1900 | } | 1898 | } |
| 1901 | 1899 | ||
| 1902 | if (nb_operands == 2) { // implicit | 1900 | if (nb_ops == 2) { // implicit |
| 1903 | operands[2] = operands[1]; | 1901 | memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2] |
| 1904 | operands[1] = operands[0]; | 1902 | memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit |
| 1905 | nb_operands = 3; | 1903 | nb_ops = 3; |
| 1906 | } | 1904 | } |
| 1907 | if (nb_operands < 3) { | 1905 | if (nb_ops < 3) { |
| 1908 | tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_operands); | 1906 | tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_ops); |
| 1909 | return; | 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 | case TOK_ASM_vnegeq_f64: | 1957 | case TOK_ASM_vnegeq_f64: |
| 1960 | opcode1 = 11; // Other" instruction | 1958 | opcode1 = 11; // Other" instruction |
| 1961 | opcode2 = 2; | 1959 | opcode2 = 2; |
| 1962 | operands[1] = 1; | 1960 | ops[1].type = OP_IM8; |
| 1963 | operand_1_register = 0; | 1961 | ops[1].e.v = 1; |
| 1964 | break; | 1962 | break; |
| 1965 | case TOK_ASM_vabseq_f32: | 1963 | case TOK_ASM_vabseq_f32: |
| 1966 | case TOK_ASM_vabseq_f64: | 1964 | case TOK_ASM_vabseq_f64: |
| 1967 | opcode1 = 11; // "Other" instruction | 1965 | opcode1 = 11; // "Other" instruction |
| 1968 | opcode2 = 6; | 1966 | opcode2 = 6; |
| 1969 | operands[1] = 0; | 1967 | ops[1].type = OP_IM8; |
| 1970 | operand_1_register = 0; | 1968 | ops[1].e.v = 0; |
| 1971 | break; | 1969 | break; |
| 1972 | case TOK_ASM_vsqrteq_f32: | 1970 | case TOK_ASM_vsqrteq_f32: |
| 1973 | case TOK_ASM_vsqrteq_f64: | 1971 | case TOK_ASM_vsqrteq_f64: |
| 1974 | opcode1 = 11; // "Other" instruction | 1972 | opcode1 = 11; // "Other" instruction |
| 1975 | opcode2 = 6; | 1973 | opcode2 = 6; |
| 1976 | operands[1] = 1; | 1974 | ops[1].type = OP_IM8; |
| 1977 | operand_1_register = 0; | 1975 | ops[1].e.v = 1; |
| 1978 | break; | 1976 | break; |
| 1979 | case TOK_ASM_vcmpeq_f32: | 1977 | case TOK_ASM_vcmpeq_f32: |
| 1980 | case TOK_ASM_vcmpeq_f64: | 1978 | case TOK_ASM_vcmpeq_f64: |
| 1981 | opcode1 = 11; // "Other" instruction | 1979 | opcode1 = 11; // "Other" instruction |
| 1982 | opcode2 = 2; | 1980 | opcode2 = 2; |
| 1983 | operands[1] = 4; | 1981 | ops[1].type = OP_IM8; |
| 1984 | operand_1_register = 0; | 1982 | ops[1].e.v = 4; |
| 1985 | break; | 1983 | break; |
| 1986 | case TOK_ASM_vcmpeeq_f32: | 1984 | case TOK_ASM_vcmpeeq_f32: |
| 1987 | case TOK_ASM_vcmpeeq_f64: | 1985 | case TOK_ASM_vcmpeeq_f64: |
| 1988 | opcode1 = 11; // "Other" instruction | 1986 | opcode1 = 11; // "Other" instruction |
| 1989 | opcode2 = 6; | 1987 | opcode2 = 6; |
| 1990 | operands[1] = 4; | 1988 | ops[1].type = OP_IM8; |
| 1991 | operand_1_register = 0; | 1989 | ops[1].e.v = 4; |
| 1992 | break; | 1990 | break; |
| 1993 | case TOK_ASM_vmoveq_f32: | 1991 | case TOK_ASM_vmoveq_f32: |
| 1994 | case TOK_ASM_vmoveq_f64: | 1992 | case TOK_ASM_vmoveq_f64: |
| 1993 | // FIXME: Check for ARM registers--and allow only very little. | ||
| 1995 | opcode1 = 11; // "Other" instruction | 1994 | opcode1 = 11; // "Other" instruction |
| 1996 | opcode2 = 2; | 1995 | opcode2 = 2; |
| 1997 | operands[1] = 0; | 1996 | ops[1].type = OP_IM8; |
| 1998 | operand_1_register = 0; | 1997 | ops[1].e.v = 0; |
| 1999 | break; | 1998 | break; |
| 2000 | // TODO: vcvt; vcvtr | 1999 | // TODO: vcvt; vcvtr |
| 2001 | default: | 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 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { | 2005 | if (coprocessor == CP_SINGLE_PRECISION_FLOAT) { |
| 2007 | if (operands[2] & 1) | 2006 | if (ops[2].type == OP_VREG32) { |
| 2008 | opcode2 |= 1; | 2007 | if (ops[2].reg & 1) |
| 2009 | operands[2] >>= 1; | 2008 | opcode2 |= 1; |
| 2009 | ops[2].reg >>= 1; | ||
| 2010 | } | ||
| 2010 | 2011 | ||
| 2011 | if (operand_1_register) { | 2012 | if (ops[1].type == OP_VREG32) { |
| 2012 | if (operands[1] & 1) | 2013 | if (ops[1].reg & 1) |
| 2013 | opcode2 |= 4; | 2014 | opcode2 |= 4; |
| 2014 | operands[1] >>= 1; | 2015 | ops[1].reg >>= 1; |
| 2015 | } | 2016 | } |
| 2016 | 2017 | ||
| 2017 | if (operands[0] & 1) | 2018 | if (ops[0].type == OP_VREG32) { |
| 2018 | opcode1 |= 4; | 2019 | if (ops[0].reg & 1) |
| 2019 | operands[0] >>= 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 | #endif | 2027 | #endif |
| 2025 | 2028 | ||