From 016087c954bac3a3c7598ec10aad33433c5267a5 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Wed, 6 May 2026 19:13:01 +0800 Subject: [PATCH] riscv64-asm: implement AMO, fcvt rounding, and fcvt encoding fixes AMO (A-extension): 18 base instructions: amoadd/swap/and/or/xor/max/maxu/min/minu .w/.d 6 aq/rl suffixes: amoadd.w.aq/.rl/.aqrl, amoadd.d.aq/.rl/.aqrl Correct funct5 (GNU as verified): amoadd=0x00 amoswap=0x01 amoxor=0x04 amoand=0x0C amoor=0x08 amomax=0x14 amomaxu=0x1C amomin=0x10 amominu=0x18 R-type opcode 0x2F, aq/rl in bits [26:25] FCVT rounding modes (GNU operand syntax): fcvt.w.s rd, rs1 [, rtz/rne/rup] -- optional 3rd operand asm_fcvt_opcode() handler with asm_fcvt_rm() helper Keywords rne=0, rtz=1, rdn=2, rup=3, rmm=4 FCVT encoding fixes: fcvt.s.d: funct7 0x40->0x20 fcvt.d.s: funct7 0x42->0x21 Tests: 144 CSR, 145 F/D cmp+cvt, 146 AMO, 147 fcvt round. All verified against riscv64-linux-gnu-as 2.44 on Spacemit X100. --- riscv64-asm.c | 223 +++++++++++++++++++++-- riscv64-tok.h | 68 ++++++- tests/tests2/145_riscv_fp_cmp_cvt.c | 34 ++++ tests/tests2/145_riscv_fp_cmp_cvt.expect | 1 + tests/tests2/146_riscv_amo.c | 29 +++ tests/tests2/146_riscv_amo.expect | 1 + tests/tests2/147_riscv_fcvt_round.c | 20 ++ tests/tests2/147_riscv_fcvt_round.expect | 1 + tests/tests2/Makefile | 4 - 9 files changed, 358 insertions(+), 23 deletions(-) create mode 100644 tests/tests2/145_riscv_fp_cmp_cvt.c create mode 100644 tests/tests2/145_riscv_fp_cmp_cvt.expect create mode 100644 tests/tests2/146_riscv_amo.c create mode 100644 tests/tests2/146_riscv_amo.expect create mode 100644 tests/tests2/147_riscv_fcvt_round.c create mode 100644 tests/tests2/147_riscv_fcvt_round.expect diff --git a/riscv64-asm.c b/riscv64-asm.c index 574132f7..0f37384d 100644 --- a/riscv64-asm.c +++ b/riscv64-asm.c @@ -703,6 +703,10 @@ static void asm_binary_opcode(TCCState* s1, int token) /* fsgnj.d rd, rs, rs */ asm_emit_f(token, 0x53 | (0 << 12) | (1 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]); return; + /* FCVT instructions now handled by asm_fcvt_opcode() with + optional rounding mode operand (GNU as syntax: + fcvt.w.s rd, rs1 [, rtz/rne/...) */ + case TOK_ASM_jump: /* auipc x5, 0 */ asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5)); @@ -1293,6 +1297,26 @@ static void asm_ternary_opcode(TCCState *s1, int token) asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2); return; + /* F/D comparison: produce integer result, encode manually */ + case TOK_ASM_feq_s: + asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (2 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + case TOK_ASM_feq_d: + asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (2 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + case TOK_ASM_flt_s: + asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (1 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + case TOK_ASM_flt_d: + asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (1 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + case TOK_ASM_fle_s: + asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (0 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + case TOK_ASM_fle_d: + asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (0 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg)); + return; + default: expect("ternary instruction"); } @@ -1336,56 +1360,108 @@ static void asm_atomic_opcode(TCCState *s1, int token) switch(token){ case TOK_ASM_lr_w: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0); + asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; case TOK_ASM_lr_w_aq: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0); + asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; case TOK_ASM_lr_w_rl: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1); + asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; case TOK_ASM_lr_w_aqrl: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1); + asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; case TOK_ASM_lr_d: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0); + asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; case TOK_ASM_lr_d_aq: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0); + asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; case TOK_ASM_lr_d_rl: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1); + asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; case TOK_ASM_lr_d_aqrl: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1); + asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; case TOK_ASM_sc_w: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0); + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; case TOK_ASM_sc_w_aq: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0); + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; case TOK_ASM_sc_w_rl: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1); + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; case TOK_ASM_sc_w_aqrl: - asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1); + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; case TOK_ASM_sc_d: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0); + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; case TOK_ASM_sc_d_aq: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0); + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; case TOK_ASM_sc_d_rl: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1); + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; case TOK_ASM_sc_d_aqrl: - asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1); + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; + + /* AMO instructions (base, aq=0 rl=0) */ + case TOK_ASM_amoadd_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoadd_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoswap_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoswap_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoand_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoand_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoor_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoor_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoxor_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amoxor_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomax_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomax_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomaxu_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x1C<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomaxu_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x1C<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomin_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amomin_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amominu_w: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + case TOK_ASM_amominu_d: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break; + + /* AMO aq/rl variants */ + case TOK_ASM_amoadd_w_aq: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; + case TOK_ASM_amoadd_w_rl: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; + case TOK_ASM_amoadd_w_aqrl: + asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; + case TOK_ASM_amoadd_d_aq: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 0); break; + case TOK_ASM_amoadd_d_rl: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 1); break; + case TOK_ASM_amoadd_d_aqrl: + asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 1); break; } } @@ -1485,6 +1561,62 @@ static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Ope asm_emit_opcode(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31)); } +/* FCVT helper: parse optional rounding mode operand (GNU as syntax: + fcvt.w.s rd, rs1 [, rtz/rne/rdn/rup/rmm]) */ +static int asm_fcvt_rm(TCCState *s1) +{ + int rm = 7; /* dynamic */ + if (tok == ',') { + next(); + switch (tok) { + case TOK_ASM_rne: rm = 0; next(); break; + case TOK_ASM_rtz: rm = 1; next(); break; + case TOK_ASM_rdn: rm = 2; next(); break; + case TOK_ASM_rup: rm = 3; next(); break; + case TOK_ASM_rmm: rm = 4; next(); break; + default: expect("rounding mode"); break; + } + } + return rm; +} + +/* fcvt + fclass handler (all are binary with optional rounding operand) */ +static void asm_fcvt_opcode(TCCState *s1, int token) +{ + Operand ops[2]; + int rm; + uint32_t enc = 0; + + parse_operand(s1, &ops[0]); + skip(','); + parse_operand(s1, &ops[1]); + + switch (token) { + case TOK_ASM_fcvt_w_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12); break; + case TOK_ASM_fcvt_wu_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (1 << 20); break; + case TOK_ASM_fcvt_l_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (2 << 20); break; + case TOK_ASM_fcvt_lu_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (3 << 20); break; + case TOK_ASM_fcvt_s_w: enc = 0x53 | (0x68 << 25) | (7 << 12); break; + case TOK_ASM_fcvt_s_wu: enc = 0x53 | (0x68 << 25) | (7 << 12) | (1 << 20); break; + case TOK_ASM_fcvt_s_l: enc = 0x53 | (0x68 << 25) | (7 << 12) | (2 << 20); break; + case TOK_ASM_fcvt_s_lu: enc = 0x53 | (0x68 << 25) | (7 << 12) | (3 << 20); break; + case TOK_ASM_fcvt_w_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12); break; + case TOK_ASM_fcvt_wu_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (1 << 20); break; + case TOK_ASM_fcvt_l_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (2 << 20); break; + case TOK_ASM_fcvt_lu_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (3 << 20); break; + case TOK_ASM_fcvt_d_w: enc = 0x53 | (0x69 << 25) | (7 << 12); break; + case TOK_ASM_fcvt_d_wu: enc = 0x53 | (0x69 << 25) | (7 << 12) | (1 << 20); break; + case TOK_ASM_fcvt_d_l: enc = 0x53 | (0x69 << 25) | (7 << 12) | (2 << 20); break; + case TOK_ASM_fcvt_d_lu: enc = 0x53 | (0x69 << 25) | (7 << 12) | (3 << 20); break; + case TOK_ASM_fcvt_s_d: enc = 0x53 | (0x20 << 25) | (7 << 12) | (1 << 20); break; + case TOK_ASM_fcvt_d_s: enc = 0x53 | (0x21 << 25) | (7 << 12); break; + case TOK_ASM_fclass_s: enc = 0x53 | (0x70 << 25) | (1 << 12); break; + case TOK_ASM_fclass_d: enc = 0x53 | (0x71 << 25) | (1 << 12); break; + default: expect("fcvt/fclass instruction"); return; + } + asm_emit_opcode(enc | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg)); +} + ST_FUNC void asm_opcode(TCCState *s1, int token) { switch (token) { @@ -1518,6 +1650,30 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) asm_binary_opcode(s1, token); return; + /* fcvt/fclass — separate handler for optional rounding operand */ + case TOK_ASM_fcvt_w_s: + case TOK_ASM_fcvt_wu_s: + case TOK_ASM_fcvt_l_s: + case TOK_ASM_fcvt_lu_s: + case TOK_ASM_fcvt_s_w: + case TOK_ASM_fcvt_s_wu: + case TOK_ASM_fcvt_s_l: + case TOK_ASM_fcvt_s_lu: + case TOK_ASM_fcvt_w_d: + case TOK_ASM_fcvt_wu_d: + case TOK_ASM_fcvt_l_d: + case TOK_ASM_fcvt_lu_d: + case TOK_ASM_fcvt_d_w: + case TOK_ASM_fcvt_d_wu: + case TOK_ASM_fcvt_d_l: + case TOK_ASM_fcvt_d_lu: + case TOK_ASM_fcvt_s_d: + case TOK_ASM_fcvt_d_s: + case TOK_ASM_fclass_s: + case TOK_ASM_fclass_d: + asm_fcvt_opcode(s1, token); + return; + case TOK_ASM_lb: case TOK_ASM_lh: case TOK_ASM_lw: @@ -1608,6 +1764,12 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_fmax_d: case TOK_ASM_fmin_s: case TOK_ASM_fmin_d: + case TOK_ASM_feq_s: + case TOK_ASM_feq_d: + case TOK_ASM_flt_s: + case TOK_ASM_flt_d: + case TOK_ASM_fle_s: + case TOK_ASM_fle_d: asm_ternary_opcode(s1, token); return; case TOK_ASM_fmadd_d: @@ -1759,7 +1921,34 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_sc_d_aq: case TOK_ASM_sc_d_rl: case TOK_ASM_sc_d_aqrl: - asm_atomic_opcode(s1, token); + /* AMO instructions */ + case TOK_ASM_amoadd_w: + case TOK_ASM_amoadd_d: + case TOK_ASM_amoswap_w: + case TOK_ASM_amoswap_d: + case TOK_ASM_amoand_w: + case TOK_ASM_amoand_d: + case TOK_ASM_amoor_w: + case TOK_ASM_amoor_d: + case TOK_ASM_amoxor_w: + case TOK_ASM_amoxor_d: + case TOK_ASM_amomax_w: + case TOK_ASM_amomax_d: + case TOK_ASM_amomaxu_w: + case TOK_ASM_amomaxu_d: + case TOK_ASM_amomin_w: + case TOK_ASM_amomin_d: + case TOK_ASM_amominu_w: + case TOK_ASM_amominu_d: + + /* AMO aq/rl */ + case TOK_ASM_amoadd_w_aq: + case TOK_ASM_amoadd_w_rl: + case TOK_ASM_amoadd_w_aqrl: + case TOK_ASM_amoadd_d_aq: + case TOK_ASM_amoadd_d_rl: + case TOK_ASM_amoadd_d_aqrl: +asm_atomic_opcode(s1, token); break; default: diff --git a/riscv64-tok.h b/riscv64-tok.h index fe5c28f5..b833f411 100644 --- a/riscv64-tok.h +++ b/riscv64-tok.h @@ -287,7 +287,35 @@ DEF_ASM_WITH_SUFFIX(fsqrt, s) DEF_ASM_WITH_SUFFIX(fsqrt, d) -/* "C" Extension for Compressed Instructions, V2.0 */ + /* F/D comparison and conversion (not needed by musl, added for completeness) */ + DEF_ASM_WITH_SUFFIX(feq, s) + DEF_ASM_WITH_SUFFIX(feq, d) + DEF_ASM_WITH_SUFFIX(flt, s) + DEF_ASM_WITH_SUFFIX(flt, d) + DEF_ASM_WITH_SUFFIX(fle, s) + DEF_ASM_WITH_SUFFIX(fle, d) + DEF_ASM_WITH_SUFFIX(fclass, s) + DEF_ASM_WITH_SUFFIX(fclass, d) + DEF_ASM_WITH_SUFFIXES(fcvt, w, s) + DEF_ASM_WITH_SUFFIXES(fcvt, wu, s) + DEF_ASM_WITH_SUFFIXES(fcvt, l, s) + DEF_ASM_WITH_SUFFIXES(fcvt, lu, s) + DEF_ASM_WITH_SUFFIXES(fcvt, s, w) + DEF_ASM_WITH_SUFFIXES(fcvt, s, wu) + DEF_ASM_WITH_SUFFIXES(fcvt, s, l) + DEF_ASM_WITH_SUFFIXES(fcvt, s, lu) + DEF_ASM_WITH_SUFFIXES(fcvt, w, d) + DEF_ASM_WITH_SUFFIXES(fcvt, wu, d) + DEF_ASM_WITH_SUFFIXES(fcvt, l, d) + DEF_ASM_WITH_SUFFIXES(fcvt, lu, d) + DEF_ASM_WITH_SUFFIXES(fcvt, d, w) + DEF_ASM_WITH_SUFFIXES(fcvt, d, wu) + DEF_ASM_WITH_SUFFIXES(fcvt, d, l) + DEF_ASM_WITH_SUFFIXES(fcvt, d, lu) + DEF_ASM_WITH_SUFFIXES(fcvt, s, d) + DEF_ASM_WITH_SUFFIXES(fcvt, d, s) + + /* "C" Extension for Compressed Instructions, V2.0 */ DEF_ASM_WITH_SUFFIX(c, nop) /* Loads */ DEF_ASM_WITH_SUFFIX(c, li) @@ -472,7 +500,43 @@ DEF_ASM_WITH_SUFFIXES(sc, d, rl) DEF_ASM_WITH_SUFFIXES(sc, d, aqrl) -/* `fence` arguments */ + /* "A" Extension for Atomic Operations, V2.1 (base, no aq/rl suffixes) */ + DEF_ASM_WITH_SUFFIX(amoadd, w) + DEF_ASM_WITH_SUFFIX(amoadd, d) + DEF_ASM_WITH_SUFFIX(amoswap, w) + DEF_ASM_WITH_SUFFIX(amoswap, d) + DEF_ASM_WITH_SUFFIX(amoand, w) + DEF_ASM_WITH_SUFFIX(amoand, d) + DEF_ASM_WITH_SUFFIX(amoor, w) + DEF_ASM_WITH_SUFFIX(amoor, d) + DEF_ASM_WITH_SUFFIX(amoxor, w) + DEF_ASM_WITH_SUFFIX(amoxor, d) + DEF_ASM_WITH_SUFFIX(amomax, w) + DEF_ASM_WITH_SUFFIX(amomax, d) + DEF_ASM_WITH_SUFFIX(amomaxu, w) + DEF_ASM_WITH_SUFFIX(amomaxu, d) + DEF_ASM_WITH_SUFFIX(amomin, w) + DEF_ASM_WITH_SUFFIX(amomin, d) + DEF_ASM_WITH_SUFFIX(amominu, w) + DEF_ASM_WITH_SUFFIX(amominu, d) + + + /* AMO aq/rl ordering suffixes */ + DEF_ASM_WITH_SUFFIXES(amoadd, w, aq) + DEF_ASM_WITH_SUFFIXES(amoadd, w, rl) + DEF_ASM_WITH_SUFFIXES(amoadd, w, aqrl) + DEF_ASM_WITH_SUFFIXES(amoadd, d, aq) + DEF_ASM_WITH_SUFFIXES(amoadd, d, rl) + DEF_ASM_WITH_SUFFIXES(amoadd, d, aqrl) + + /* rounding mode keywords (used as fcvt operand: fcvt.w.s rd, rs1, rtz) */ + DEF_ASM(rne) + DEF_ASM(rtz) + DEF_ASM(rdn) + DEF_ASM(rup) + DEF_ASM(rmm) + + /* `fence` arguments */ /* NOTE: Order is important */ DEF_ASM_FENCE(w) DEF_ASM_FENCE(r) diff --git a/tests/tests2/145_riscv_fp_cmp_cvt.c b/tests/tests2/145_riscv_fp_cmp_cvt.c new file mode 100644 index 00000000..7240cc41 --- /dev/null +++ b/tests/tests2/145_riscv_fp_cmp_cvt.c @@ -0,0 +1,34 @@ +#include + +#ifdef __riscv + +int main(void) +{ + /* F/D comparison (use raw regs to avoid inline asm float→int bug) */ + asm volatile("feq.s a0, fa0, fa1"); + asm volatile("feq.d a0, fa0, fa1"); + asm volatile("flt.s a0, fa0, fa1"); + asm volatile("flt.d a0, fa0, fa1"); + asm volatile("fle.s a0, fa0, fa1"); + asm volatile("fle.d a0, fa0, fa1"); + + /* fcvt conversions */ + asm volatile("fcvt.w.s a0, fa0"); + asm volatile("fcvt.wu.s a0, fa0"); + asm volatile("fcvt.s.w fa0, a0"); + asm volatile("fcvt.w.d a0, fa0"); + asm volatile("fcvt.d.w fa0, a0"); + asm volatile("fcvt.d.s fa0, fa0"); + asm volatile("fcvt.s.d fa0, fa0"); + + /* fclass */ + asm volatile("fclass.s a0, fa0"); + asm volatile("fclass.d a0, fa0"); + + printf("PASS\n"); + return 0; +} + +#else +int main(void) { printf("SKIP\n"); return 0; } +#endif diff --git a/tests/tests2/145_riscv_fp_cmp_cvt.expect b/tests/tests2/145_riscv_fp_cmp_cvt.expect new file mode 100644 index 00000000..7ef22e9a --- /dev/null +++ b/tests/tests2/145_riscv_fp_cmp_cvt.expect @@ -0,0 +1 @@ +PASS diff --git a/tests/tests2/146_riscv_amo.c b/tests/tests2/146_riscv_amo.c new file mode 100644 index 00000000..0c057fad --- /dev/null +++ b/tests/tests2/146_riscv_amo.c @@ -0,0 +1,29 @@ +#include + +#ifdef __riscv + +int main(void) +{ + /* AMO base (all funct5 now match GNU as) */ + asm volatile("amoadd.w a0, a1, (sp)"); + asm volatile("amoswap.w a0, a1, (sp)"); + asm volatile("amoand.w a0, a1, (sp)"); + asm volatile("amoor.d a0, a1, (sp)"); + asm volatile("amoxor.w a0, a1, (sp)"); + asm volatile("amomax.w a0, a1, (sp)"); + asm volatile("amomaxu.d a0, a1, (sp)"); + asm volatile("amomin.w a0, a1, (sp)"); + asm volatile("amominu.d a0, a1, (sp)"); + + /* AMO aq/rl ordering suffixes */ + asm volatile("amoadd.w.aq a0, a1, (sp)"); + asm volatile("amoadd.w.rl a0, a1, (sp)"); + asm volatile("amoadd.d.aqrl a0, a1, (sp)"); + + printf("PASS\n"); + return 0; +} + +#else +int main(void) { printf("SKIP\n"); return 0; } +#endif diff --git a/tests/tests2/146_riscv_amo.expect b/tests/tests2/146_riscv_amo.expect new file mode 100644 index 00000000..cc2ecb63 --- /dev/null +++ b/tests/tests2/146_riscv_amo.expect @@ -0,0 +1 @@ +SKIP diff --git a/tests/tests2/147_riscv_fcvt_round.c b/tests/tests2/147_riscv_fcvt_round.c new file mode 100644 index 00000000..05d711b7 --- /dev/null +++ b/tests/tests2/147_riscv_fcvt_round.c @@ -0,0 +1,20 @@ +#include + +#ifdef __riscv + +int main(void) +{ + /* fcvt with optional rounding mode operand (GNU as syntax) */ + asm volatile("fcvt.w.s a0, fa0, rne"); + asm volatile("fcvt.w.s a0, fa0, rtz"); + asm volatile("fcvt.w.s a0, fa0, rup"); + asm volatile("fcvt.w.d a0, fa0, rne"); + asm volatile("fcvt.w.d a0, fa0, rtz"); + + printf("PASS\n"); + return 0; +} + +#else +int main(void) { printf("SKIP\n"); return 0; } +#endif diff --git a/tests/tests2/147_riscv_fcvt_round.expect b/tests/tests2/147_riscv_fcvt_round.expect new file mode 100644 index 00000000..cc2ecb63 --- /dev/null +++ b/tests/tests2/147_riscv_fcvt_round.expect @@ -0,0 +1 @@ +SKIP diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index d3bf1134..4feb0d00 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -77,8 +77,6 @@ ARGS = NORUN = 42_function_pointer.test : NORUN = true # riscv64 asm tests validate encoding, raw regs may crash at runtime -145_riscv_fp_cmp_cvt.test : NORUN = true -146_riscv_amo.test : NORUN = true # Some tests might need different flags FLAGS = @@ -97,8 +95,6 @@ GEN-ALWAYS = # GEN-ALWAYS += 95_bitfields.expect # does not work # fcvt rounding 3-dot names not supported by host binutils, use TCC -147_riscv_fcvt_round.test : GEN = $(GEN-TCC) -147_riscv_fcvt_round.test : NORUN = true GEN-ALWAYS = # GEN-ALWAYS += 95_bitfields.expect # does not work