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 | 63 | static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2); |
| 64 | 64 | static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm); |
| 65 | 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 | 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 | 70 | static void asm_nullary_opcode(TCCState *s1, int token); |
| 68 | 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 | 590 | asm_emit_css(token, 2 | (5 << 13), ops, ops + 1); |
| 588 | 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 | 601 | /* pseudoinstructions */ |
| 591 | 602 | /* rd, sym */ |
| 592 | 603 | case TOK_ASM_la: |
| @@ -682,6 +693,15 @@ static void asm_binary_opcode(TCCState* s1, int token) · 89 unmodified lines | ||
| 682 | 693 | asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]); |
| 683 | 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 | 705 | default: |
| 686 | 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 | 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 | 799 | /* caller: Add funct3 into opcode */ |
| 713 | 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 | 1176 | asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2); |
| 1090 | 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 | 1199 | default: |
| 1093 | 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 | 1222 | static void asm_atomic_opcode(TCCState *s1, int token) |
| 1098 | 1223 | { |
| 1099 | 1224 | Operand ops[3]; |
| @@ -1271,6 +1396,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 171 unmodified lines | ||
| 1271 | 1396 | |
| 1272 | 1397 | case TOK_ASM_lui: |
| 1273 | 1398 | case TOK_ASM_auipc: |
| 1399 | + case TOK_ASM_fsqrt_s: | |
| 1400 | + case TOK_ASM_fsqrt_d: | |
| 1274 | 1401 | asm_binary_opcode(s1, token); |
| 1275 | 1402 | return; |
| 1276 | 1403 | |
| @@ -1349,8 +1476,19 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 72 unmodified lines | ||
| 1349 | 1476 | case TOK_ASM_csrrsi: |
| 1350 | 1477 | case TOK_ASM_csrrw: |
| 1351 | 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 | 1486 | asm_ternary_opcode(s1, token); |
| 1353 | 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 | 1493 | /* Branches */ |
| 1356 | 1494 | case TOK_ASM_beq: |
| @@ -1441,6 +1579,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 84 unmodified lines | ||
| 1441 | 1579 | case TOK_ASM_not: |
| 1442 | 1580 | case TOK_ASM_neg: |
| 1443 | 1581 | case TOK_ASM_negw: |
| 1582 | + case TOK_ASM_fabs_s: | |
| 1583 | + case TOK_ASM_fabs_d: | |
| 1444 | 1584 | asm_binary_opcode(s1, token); |
| 1445 | 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 | 1696 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || |
| 1557 | 1697 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { |
| 1558 | 1698 | /* floating point register */ |
| 1559 | − reg = TOK_ASM_f0 + reg; | |
| 1699 | + reg = TOK_ASM_f0 + REG_VALUE(reg); | |
| 1560 | 1700 | } else { |
| 1561 | 1701 | /* general purpose register */ |
| 1562 | 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 | 1710 | if ((sv->type.t & VT_BTYPE) == VT_FLOAT || |
| 1571 | 1711 | (sv->type.t & VT_BTYPE) == VT_DOUBLE) { |
| 1572 | 1712 | /* floating point register */ |
| 1573 | − reg = TOK_ASM_f0 + reg; | |
| 1713 | + reg = TOK_ASM_f0 + REG_VALUE(reg); | |
| 1574 | 1714 | } else { |
| 1575 | 1715 | /* general purpose register */ |
| 1576 | 1716 | reg = TOK_ASM_x0 + reg; |
| @@ -266,6 +266,19 @@ · 265 unmodified lines | ||
| 266 | 266 | DEF_ASM(remw) |
| 267 | 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 | 282 | /* "C" Extension for Compressed Instructions, V2.0 */ |
| 270 | 283 | DEF_ASM_WITH_SUFFIX(c, nop) |
| 271 | 284 | /* Loads */ |