Adds the 8 most essential floating-point arithmetic instructions: fadd.s/d, fsub.s/d, fmul.s/d, fdiv.s/d, for both single and double precision. These complement the existing fsgnj/fmax/fmin/fsqrt set. Comparison (feq/flt/fle) and conversion (fcvt) instructions remain as future work.
Unified · Split
| @@ -1229,6 +1229,30 @@ static void asm_ternary_opcode(TCCState *s1, int token) · 1228 unmodified lines | |||
| 1229 | return; | 1229 | return; |
| 1230 | 1230 | ||
| 1231 | /* F/D extension */ | 1231 | /* F/D extension */ |
| 1232 | case TOK_ASM_fadd_d: | ||
| 1233 | asm_emit_f(token, 0x53 | (0 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1234 | return; | ||
| 1235 | case TOK_ASM_fadd_s: | ||
| 1236 | asm_emit_f(token, 0x53 | (0 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1237 | return; | ||
| 1238 | case TOK_ASM_fsub_d: | ||
| 1239 | asm_emit_f(token, 0x53 | (1 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1240 | return; | ||
| 1241 | case TOK_ASM_fsub_s: | ||
| 1242 | asm_emit_f(token, 0x53 | (1 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1243 | return; | ||
| 1244 | case TOK_ASM_fmul_d: | ||
| 1245 | asm_emit_f(token, 0x53 | (2 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1246 | return; | ||
| 1247 | case TOK_ASM_fmul_s: | ||
| 1248 | asm_emit_f(token, 0x53 | (2 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1249 | return; | ||
| 1250 | case TOK_ASM_fdiv_d: | ||
| 1251 | asm_emit_f(token, 0x53 | (3 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1252 | return; | ||
| 1253 | case TOK_ASM_fdiv_s: | ||
| 1254 | asm_emit_f(token, 0x53 | (3 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2); | ||
| 1255 | return; | ||
| 1232 | case TOK_ASM_fsgnj_d: | 1256 | case TOK_ASM_fsgnj_d: |
| 1233 | asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2); | 1257 | asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2); |
| 1234 | return; | 1258 | return; |
| @@ -1549,6 +1573,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 314 unmodified lines | |||
| 1549 | case TOK_ASM_csrrw: | 1573 | case TOK_ASM_csrrw: |
| 1550 | case TOK_ASM_csrrwi: | 1574 | case TOK_ASM_csrrwi: |
| 1551 | /* F/D extension */ | 1575 | /* F/D extension */ |
| 1576 | case TOK_ASM_fadd_s: | ||
| 1577 | case TOK_ASM_fadd_d: | ||
| 1578 | case TOK_ASM_fsub_s: | ||
| 1579 | case TOK_ASM_fsub_d: | ||
| 1580 | case TOK_ASM_fmul_s: | ||
| 1581 | case TOK_ASM_fmul_d: | ||
| 1582 | case TOK_ASM_fdiv_s: | ||
| 1583 | case TOK_ASM_fdiv_d: | ||
| 1552 | case TOK_ASM_fsgnj_d: | 1584 | case TOK_ASM_fsgnj_d: |
| 1553 | case TOK_ASM_fsgnj_s: | 1585 | case TOK_ASM_fsgnj_s: |
| 1554 | case TOK_ASM_fmax_s: | 1586 | case TOK_ASM_fmax_s: |
| @@ -270,6 +270,14 @@ · 269 unmodified lines | |||
| 270 | /* enough implemented for musl */ | 270 | /* enough implemented for musl */ |
| 271 | DEF_ASM_WITH_SUFFIX(fsgnj, s) | 271 | DEF_ASM_WITH_SUFFIX(fsgnj, s) |
| 272 | DEF_ASM_WITH_SUFFIX(fsgnj, d) | 272 | DEF_ASM_WITH_SUFFIX(fsgnj, d) |
| 273 | DEF_ASM_WITH_SUFFIX(fadd, s) | ||
| 274 | DEF_ASM_WITH_SUFFIX(fadd, d) | ||
| 275 | DEF_ASM_WITH_SUFFIX(fsub, s) | ||
| 276 | DEF_ASM_WITH_SUFFIX(fsub, d) | ||
| 277 | DEF_ASM_WITH_SUFFIX(fmul, s) | ||
| 278 | DEF_ASM_WITH_SUFFIX(fmul, d) | ||
| 279 | DEF_ASM_WITH_SUFFIX(fdiv, s) | ||
| 280 | DEF_ASM_WITH_SUFFIX(fdiv, d) | ||
| 273 | DEF_ASM_WITH_SUFFIX(fmadd, s) | 281 | DEF_ASM_WITH_SUFFIX(fmadd, s) |
| 274 | DEF_ASM_WITH_SUFFIX(fmadd, d) | 282 | DEF_ASM_WITH_SUFFIX(fmadd, d) |
| 275 | DEF_ASM_WITH_SUFFIX(fmax, s) | 283 | DEF_ASM_WITH_SUFFIX(fmax, s) |
| @@ -0,0 +1,112 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | |||
| 3 | /* P1.3: riscv64 F/D extension arithmetic instructions. | ||
| 4 | Tests fadd/fsub/fmul/fdiv for both single and double precision. */ | ||
| 5 | |||
| 6 | #ifdef __riscv | ||
| 7 | |||
| 8 | float test_fadd_s(float a, float b) | ||
| 9 | { | ||
| 10 | float r; | ||
| 11 | asm("fadd.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 12 | return r; | ||
| 13 | } | ||
| 14 | |||
| 15 | float test_fsub_s(float a, float b) | ||
| 16 | { | ||
| 17 | float r; | ||
| 18 | asm("fsub.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 19 | return r; | ||
| 20 | } | ||
| 21 | |||
| 22 | float test_fmul_s(float a, float b) | ||
| 23 | { | ||
| 24 | float r; | ||
| 25 | asm("fmul.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 26 | return r; | ||
| 27 | } | ||
| 28 | |||
| 29 | float test_fdiv_s(float a, float b) | ||
| 30 | { | ||
| 31 | float r; | ||
| 32 | asm("fdiv.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 33 | return r; | ||
| 34 | } | ||
| 35 | |||
| 36 | double test_fadd_d(double a, double b) | ||
| 37 | { | ||
| 38 | double r; | ||
| 39 | asm("fadd.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 40 | return r; | ||
| 41 | } | ||
| 42 | |||
| 43 | double test_fsub_d(double a, double b) | ||
| 44 | { | ||
| 45 | double r; | ||
| 46 | asm("fsub.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 47 | return r; | ||
| 48 | } | ||
| 49 | |||
| 50 | double test_fmul_d(double a, double b) | ||
| 51 | { | ||
| 52 | double r; | ||
| 53 | asm("fmul.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 54 | return r; | ||
| 55 | } | ||
| 56 | |||
| 57 | double test_fdiv_d(double a, double b) | ||
| 58 | { | ||
| 59 | double r; | ||
| 60 | asm("fdiv.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b)); | ||
| 61 | return r; | ||
| 62 | } | ||
| 63 | |||
| 64 | int main(void) | ||
| 65 | { | ||
| 66 | int ok = 1; | ||
| 67 | |||
| 68 | if (test_fadd_s(1.5f, 2.5f) != 4.0f) { | ||
| 69 | printf("FAIL: fadd.s\n"); | ||
| 70 | ok = 0; | ||
| 71 | } | ||
| 72 | if (test_fsub_s(5.0f, 2.0f) != 3.0f) { | ||
| 73 | printf("FAIL: fsub.s\n"); | ||
| 74 | ok = 0; | ||
| 75 | } | ||
| 76 | if (test_fmul_s(3.0f, 4.0f) != 12.0f) { | ||
| 77 | printf("FAIL: fmul.s\n"); | ||
| 78 | ok = 0; | ||
| 79 | } | ||
| 80 | if (test_fdiv_s(12.0f, 4.0f) != 3.0f) { | ||
| 81 | printf("FAIL: fdiv.s\n"); | ||
| 82 | ok = 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (test_fadd_d(1.5, 2.5) != 4.0) { | ||
| 86 | printf("FAIL: fadd.d\n"); | ||
| 87 | ok = 0; | ||
| 88 | } | ||
| 89 | if (test_fsub_d(5.0, 2.0) != 3.0) { | ||
| 90 | printf("FAIL: fsub.d\n"); | ||
| 91 | ok = 0; | ||
| 92 | } | ||
| 93 | if (test_fmul_d(3.0, 4.0) != 12.0) { | ||
| 94 | printf("FAIL: fmul.d\n"); | ||
| 95 | ok = 0; | ||
| 96 | } | ||
| 97 | if (test_fdiv_d(12.0, 4.0) != 3.0) { | ||
| 98 | printf("FAIL: fdiv.d\n"); | ||
| 99 | ok = 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | printf("%s\n", ok ? "PASS" : "FAIL"); | ||
| 103 | return ok ? 0 : 1; | ||
| 104 | } | ||
| 105 | |||
| 106 | #else | ||
| 107 | int main(void) | ||
| 108 | { | ||
| 109 | printf("SKIP\n"); | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | #endif | ||
| @@ -0,0 +1 @@ | |||
| 1 | PASS | ||