This patch implements some instructions required by musl 1.1.24.
Unified · Split
| @@ -63,6 +63,9 @@ static void asm_emit_opcode(uint32_t opcode); · 62 unmodified lines | |||
| 63 | static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2); | 63 | static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2); |
| 64 | static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm); | 64 | static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm); |
| 65 | static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2); | 65 | static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2); |
| 66 | static void asm_emit_f(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2); | ||
| 67 | static void asm_emit_fb(int token, uint32_t opcode, const Operand *rd, const Operand *rs); | ||
| 68 | static void asm_emit_fq(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2, const Operand *rs3); | ||
| 66 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); | 69 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); |
| 67 | static void asm_nullary_opcode(TCCState *s1, int token); | 70 | static void asm_nullary_opcode(TCCState *s1, int token); |
| 68 | ST_FUNC void asm_opcode(TCCState *s1, int token); | 71 | ST_FUNC void asm_opcode(TCCState *s1, int token); |
| @@ -587,6 +590,14 @@ static void asm_binary_opcode(TCCState* s1, int token) · 518 unmodified lines | |||
| 587 | asm_emit_css(token, 2 | (5 << 13), ops, ops + 1); | 590 | asm_emit_css(token, 2 | (5 << 13), ops, ops + 1); |
| 588 | return; | 591 | return; |
| 589 | 592 | ||
| 593 | /* F/D extension */ | ||
| 594 | case TOK_ASM_fsqrt_d: | ||
| 595 | asm_emit_fb(token, 0x53 | (11 << 27) | (1 << 25) | (7 << 12), ops, ops + 1); | ||
| 596 | return; | ||
| 597 | case TOK_ASM_fsqrt_s: | ||
| 598 | asm_emit_fb(token, 0x53 | (11 << 27) | (0 << 25) | (7 << 12), ops, ops + 1); | ||
| 599 | return; | ||
| 600 | |||
| 590 | /* pseudoinstructions */ | 601 | /* pseudoinstructions */ |
| 591 | /* rd, sym */ | 602 | /* rd, sym */ |
| 592 | case TOK_ASM_la: | 603 | case TOK_ASM_la: |
| @@ -682,6 +693,15 @@ static void asm_binary_opcode(TCCState* s1, int token) · 89 unmodified lines | |||
| 682 | asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]); | 693 | asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]); |
| 683 | return; | 694 | return; |
| 684 | 695 | ||
| 696 | case TOK_ASM_fabs_d: | ||
| 697 | /* fsgnjx.d rd, rs, rs */ | ||
| 698 | asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]); | ||
| 699 | return; | ||
| 700 | case TOK_ASM_fabs_s: | ||
| 701 | /* fsgnjx.s rd, rs, rs */ | ||
| 702 | asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]); | ||
| 703 | return; | ||
| 704 | |||
| 685 | default: | 705 | default: |
| 686 | expect("binary instruction"); | 706 | expect("binary instruction"); |
| 687 | } | 707 | } |
| @@ -709,6 +729,73 @@ static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Oper · 21 unmodified lines | |||
| 709 | gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg)); | 729 | gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg)); |
| 710 | } | 730 | } |
| 711 | 731 | ||
| 732 | /* caller: Add rounding mode, fmt, funct5 to opcode */ | ||
| 733 | static void asm_emit_f(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2) | ||
| 734 | { | ||
| 735 | if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) { | ||
| 736 | tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 737 | } | ||
| 738 | if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) { | ||
| 739 | tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 740 | } | ||
| 741 | if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) { | ||
| 742 | tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 743 | } | ||
| 744 | /* F-type instruction: | ||
| 745 | 31...27 funct5 | ||
| 746 | 26...25 fmt | ||
| 747 | 24...20 rs2 | ||
| 748 | 19...15 rs1 | ||
| 749 | 14...12 rm | ||
| 750 | 11...7 rd | ||
| 751 | 6...0 opcode = OP-FP */ | ||
| 752 | gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg)); | ||
| 753 | } | ||
| 754 | /* caller: Add rounding mode, fmt, funct5 to opcode */ | ||
| 755 | static void asm_emit_fb(int token, uint32_t opcode, const Operand* rd, const Operand* rs) | ||
| 756 | { | ||
| 757 | if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) { | ||
| 758 | tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 759 | } | ||
| 760 | if (rs->type != OP_REG || !REG_IS_FLOAT(rs->reg)) { | ||
| 761 | tcc_error("'%s': Expected source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 762 | } | ||
| 763 | /* F-type instruction: | ||
| 764 | 31...27 funct5 | ||
| 765 | 26...25 fmt | ||
| 766 | 24...20 rs2 = 0 | ||
| 767 | 19...15 rs1 = rs | ||
| 768 | 14...12 rm | ||
| 769 | 11...7 rd | ||
| 770 | 6...0 opcode = OP-FP */ | ||
| 771 | gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs->reg) | ENCODE_RS2(0)); | ||
| 772 | } | ||
| 773 | /* caller: Add rounding mode, fmt to opcode */ | ||
| 774 | static void asm_emit_fq(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2, const Operand* rs3) | ||
| 775 | { | ||
| 776 | if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) { | ||
| 777 | tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 778 | } | ||
| 779 | if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) { | ||
| 780 | tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 781 | } | ||
| 782 | if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) { | ||
| 783 | tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 784 | } | ||
| 785 | if (rs3->type != OP_REG || !REG_IS_FLOAT(rs3->reg)) { | ||
| 786 | tcc_error("'%s': Expected third source operand that is a floating-point register", get_tok_str(token, NULL)); | ||
| 787 | } | ||
| 788 | /* F-type instruction: | ||
| 789 | 31...27 rs3 | ||
| 790 | 26...25 fmt | ||
| 791 | 24...20 rs2 | ||
| 792 | 19...15 rs1 | ||
| 793 | 14...12 rm | ||
| 794 | 11...7 rd | ||
| 795 | 6...0 opcode */ | ||
| 796 | gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (REG_VALUE(rs3->reg) << 27)); | ||
| 797 | } | ||
| 798 | |||
| 712 | /* caller: Add funct3 into opcode */ | 799 | /* caller: Add funct3 into opcode */ |
| 713 | static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2) | 800 | static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2) |
| 714 | { | 801 | { |
| @@ -1089,11 +1176,49 @@ static void asm_ternary_opcode(TCCState *s1, int token) · 374 unmodified lines | |||
| 1089 | asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2); | 1176 | asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2); |
| 1090 | return; | 1177 | return; |
| 1091 | 1178 | ||
| 1179 | /* F/D extension */ | ||
| 1180 | case TOK_ASM_fsgnj_d: | ||
| 1181 | asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2); | ||
| 1182 | return; | ||
| 1183 | case TOK_ASM_fsgnj_s: | ||
| 1184 | asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2); | ||
| 1185 | return; | ||
| 1186 | case TOK_ASM_fmax_d: | ||
| 1187 | asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (1 << 12), ops, ops + 1, ops + 2); | ||
| 1188 | return; | ||
| 1189 | case TOK_ASM_fmax_s: | ||
| 1190 | asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (1 << 12), ops, ops + 1, ops + 2); | ||
| 1191 | return; | ||
| 1192 | case TOK_ASM_fmin_d: | ||
| 1193 | asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2); | ||
| 1194 | return; | ||
| 1195 | case TOK_ASM_fmin_s: | ||
| 1196 | asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2); | ||
| 1197 | return; | ||
| 1198 | |||
| 1092 | default: | 1199 | default: |
| 1093 | expect("ternary instruction"); | 1200 | expect("ternary instruction"); |
| 1094 | } | 1201 | } |
| 1095 | } | 1202 | } |
| 1096 | 1203 | ||
| 1204 | static void asm_quaternary_opcode(TCCState *s1, int token) | ||
| 1205 | { | ||
| 1206 | Operand ops[4]; | ||
| 1207 | parse_operands(s1, &ops[0], 4); | ||
| 1208 | |||
| 1209 | switch (token) { | ||
| 1210 | case TOK_ASM_fmadd_d: | ||
| 1211 | asm_emit_fq(token, 0x43 | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3); | ||
| 1212 | return; | ||
| 1213 | case TOK_ASM_fmadd_s: | ||
| 1214 | asm_emit_fq(token, 0x43 | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3); | ||
| 1215 | return; | ||
| 1216 | |||
| 1217 | default: | ||
| 1218 | expect("quaternary instruction"); | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | |||
| 1097 | static void asm_atomic_opcode(TCCState *s1, int token) | 1222 | static void asm_atomic_opcode(TCCState *s1, int token) |
| 1098 | { | 1223 | { |
| 1099 | Operand ops[3]; | 1224 | Operand ops[3]; |
| @@ -1271,6 +1396,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 171 unmodified lines | |||
| 1271 | 1396 | ||
| 1272 | case TOK_ASM_lui: | 1397 | case TOK_ASM_lui: |
| 1273 | case TOK_ASM_auipc: | 1398 | case TOK_ASM_auipc: |
| 1399 | case TOK_ASM_fsqrt_s: | ||
| 1400 | case TOK_ASM_fsqrt_d: | ||
| 1274 | asm_binary_opcode(s1, token); | 1401 | asm_binary_opcode(s1, token); |
| 1275 | return; | 1402 | return; |
| 1276 | 1403 | ||
| @@ -1349,8 +1476,19 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 72 unmodified lines | |||
| 1349 | case TOK_ASM_csrrsi: | 1476 | case TOK_ASM_csrrsi: |
| 1350 | case TOK_ASM_csrrw: | 1477 | case TOK_ASM_csrrw: |
| 1351 | case TOK_ASM_csrrwi: | 1478 | case TOK_ASM_csrrwi: |
| 1479 | /* F/D extension */ | ||
| 1480 | case TOK_ASM_fsgnj_d: | ||
| 1481 | case TOK_ASM_fsgnj_s: | ||
| 1482 | case TOK_ASM_fmax_s: | ||
| 1483 | case TOK_ASM_fmax_d: | ||
| 1484 | case TOK_ASM_fmin_s: | ||
| 1485 | case TOK_ASM_fmin_d: | ||
| 1352 | asm_ternary_opcode(s1, token); | 1486 | asm_ternary_opcode(s1, token); |
| 1353 | return; | 1487 | return; |
| 1488 | case TOK_ASM_fmadd_d: | ||
| 1489 | case TOK_ASM_fmadd_s: | ||
| 1490 | asm_quaternary_opcode(s1, token); | ||
| 1491 | return; | ||
| 1354 | 1492 | ||
| 1355 | /* Branches */ | 1493 | /* Branches */ |
| 1356 | case TOK_ASM_beq: | 1494 | case TOK_ASM_beq: |
| @@ -1441,6 +1579,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 84 unmodified lines | |||
| 1441 | case TOK_ASM_not: | 1579 | case TOK_ASM_not: |
| 1442 | case TOK_ASM_neg: | 1580 | case TOK_ASM_neg: |
| 1443 | case TOK_ASM_negw: | 1581 | case TOK_ASM_negw: |
| 1582 | case TOK_ASM_fabs_s: | ||
| 1583 | case TOK_ASM_fabs_d: | ||
| 1444 | asm_binary_opcode(s1, token); | 1584 | asm_binary_opcode(s1, token); |
| 1445 | return; | 1585 | return; |
| 1446 | 1586 | ||
| @@ -1556,7 +1696,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) · 109 unmodified lines | |||
| 1556 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || | 1696 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || |
| 1557 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { | 1697 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { |
| 1558 | /* floating point register */ | 1698 | /* floating point register */ |
| 1559 | reg = TOK_ASM_f0 + reg; | 1699 | reg = TOK_ASM_f0 + REG_VALUE(reg); |
| 1560 | } else { | 1700 | } else { |
| 1561 | /* general purpose register */ | 1701 | /* general purpose register */ |
| 1562 | reg = TOK_ASM_x0 + reg; | 1702 | reg = TOK_ASM_x0 + reg; |
| @@ -1570,7 +1710,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) · 7 unmodified lines | |||
| 1570 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || | 1710 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || |
| 1571 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { | 1711 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { |
| 1572 | /* floating point register */ | 1712 | /* floating point register */ |
| 1573 | reg = TOK_ASM_f0 + reg; | 1713 | reg = TOK_ASM_f0 + REG_VALUE(reg); |
| 1574 | } else { | 1714 | } else { |
| 1575 | /* general purpose register */ | 1715 | /* general purpose register */ |
| 1576 | reg = TOK_ASM_x0 + reg; | 1716 | reg = TOK_ASM_x0 + reg; |
| @@ -266,6 +266,19 @@ · 265 unmodified lines | |||
| 266 | DEF_ASM(remw) | 266 | DEF_ASM(remw) |
| 267 | DEF_ASM(remuw) | 267 | DEF_ASM(remuw) |
| 268 | 268 | ||
| 269 | /* "F"/"D" Extension for Single/Double-Precision Floating Point Arithmetic, V2.2 */ | ||
| 270 | /* enough implemented for musl */ | ||
| 271 | DEF_ASM_WITH_SUFFIX(fsgnj, s) | ||
| 272 | DEF_ASM_WITH_SUFFIX(fsgnj, d) | ||
| 273 | DEF_ASM_WITH_SUFFIX(fmadd, s) | ||
| 274 | DEF_ASM_WITH_SUFFIX(fmadd, d) | ||
| 275 | DEF_ASM_WITH_SUFFIX(fmax, s) | ||
| 276 | DEF_ASM_WITH_SUFFIX(fmax, d) | ||
| 277 | DEF_ASM_WITH_SUFFIX(fmin, s) | ||
| 278 | DEF_ASM_WITH_SUFFIX(fmin, d) | ||
| 279 | DEF_ASM_WITH_SUFFIX(fsqrt, s) | ||
| 280 | DEF_ASM_WITH_SUFFIX(fsqrt, d) | ||
| 281 | |||
| 269 | /* "C" Extension for Compressed Instructions, V2.0 */ | 282 | /* "C" Extension for Compressed Instructions, V2.0 */ |
| 270 | DEF_ASM_WITH_SUFFIX(c, nop) | 283 | DEF_ASM_WITH_SUFFIX(c, nop) |
| 271 | /* Loads */ | 284 | /* Loads */ |