mirror of
https://github.com/TinyCC/tinycc.git
synced 2026-05-12 20:05:45 +00:00
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.
This commit is contained in:
223
riscv64-asm.c
223
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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
34
tests/tests2/145_riscv_fp_cmp_cvt.c
Normal file
34
tests/tests2/145_riscv_fp_cmp_cvt.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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
|
||||
1
tests/tests2/145_riscv_fp_cmp_cvt.expect
Normal file
1
tests/tests2/145_riscv_fp_cmp_cvt.expect
Normal file
@@ -0,0 +1 @@
|
||||
PASS
|
||||
29
tests/tests2/146_riscv_amo.c
Normal file
29
tests/tests2/146_riscv_amo.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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
|
||||
1
tests/tests2/146_riscv_amo.expect
Normal file
1
tests/tests2/146_riscv_amo.expect
Normal file
@@ -0,0 +1 @@
|
||||
SKIP
|
||||
20
tests/tests2/147_riscv_fcvt_round.c
Normal file
20
tests/tests2/147_riscv_fcvt_round.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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
|
||||
1
tests/tests2/147_riscv_fcvt_round.expect
Normal file
1
tests/tests2/147_riscv_fcvt_round.expect
Normal file
@@ -0,0 +1 @@
|
||||
SKIP
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user