riscv64-asm: implement pseudo-instructions sext.w, fmv, fneg

sext.w: addiw rd, rs, 0 (sign-extend 32-bit word)
fmv.s/fmv.d: fsgnj.s/d rd, rs, rs (float register move)
fneg.s/fneg.d: fsgnjn.s/d rd, rs, rs (float register negate)

These were defined in riscv64-tok.h but had no handler code.
CSR pseudo-instructions (csrr, csrw, csrci, csrsi, csrwi) skipped
for now — they require CSR operand parsing in binary mode.
This commit is contained in:
Meng Zhuo 2026-05-03 00:31:10 +08:00
parent 2a33daedca
commit 273978b927
3 changed files with 126 additions and 0 deletions

View File

@ -683,6 +683,26 @@ static void asm_binary_opcode(TCCState* s1, int token)
/* subw rd, x0, rs2 */
asm_emit_r(token, (0xE << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
return;
case TOK_ASM_sext_w:
/* addiw rd, rs, 0 */
asm_emit_i(token, 0x1b, &ops[0], &ops[1], &zimm);
return;
case TOK_ASM_fneg_s:
/* fsgnjn.s rd, rs, rs */
asm_emit_f(token, 0x53 | (1 << 12) | (0 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fneg_d:
/* fsgnjn.d rd, rs, rs */
asm_emit_f(token, 0x53 | (1 << 12) | (1 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fmv_s:
/* fsgnj.s rd, rs, rs */
asm_emit_f(token, 0x53 | (0 << 12) | (0 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fmv_d:
/* fsgnj.d rd, rs, rs */
asm_emit_f(token, 0x53 | (0 << 12) | (1 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_jump:
/* auipc x5, 0 */
asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5));
@ -1634,8 +1654,13 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_not:
case TOK_ASM_neg:
case TOK_ASM_negw:
case TOK_ASM_sext_w:
case TOK_ASM_fabs_s:
case TOK_ASM_fabs_d:
case TOK_ASM_fmv_s:
case TOK_ASM_fmv_d:
case TOK_ASM_fneg_s:
case TOK_ASM_fneg_d:
case TOK_ASM_csrc:
case TOK_ASM_csrs:
case TOK_ASM_fsrm:

View File

@ -0,0 +1,100 @@
#include <stdio.h>
/* P0.4 + P1.4: riscv64 asm pseudo-instructions test.
Exercises neg/negw, sext.w, fmv.s/d, fneg.s/d. */
#ifdef __riscv
int test_neg(int x)
{
int r;
asm("neg %0, %1" : "=r"(r) : "r"(x));
return r;
}
long long test_negw(long long x)
{
int r;
asm("negw %0, %1" : "=r"(r) : "r"((int)x));
return (long long)r;
}
long long test_sextw(int x)
{
long long r;
asm("sext.w %0, %1" : "=r"(r) : "r"(x));
return r;
}
float test_fmv_s(float a)
{
float r;
asm("fmv.s %0, %1" : "=f"(r) : "f"(a));
return r;
}
float test_fneg_s(float a)
{
float r;
asm("fneg.s %0, %1" : "=f"(r) : "f"(a));
return r;
}
double test_fmv_d(double a)
{
double r;
asm("fmv.d %0, %1" : "=f"(r) : "f"(a));
return r;
}
double test_fneg_d(double a)
{
double r;
asm("fneg.d %0, %1" : "=f"(r) : "f"(a));
return r;
}
int main(void)
{
int ok = 1;
if (test_neg(42) != -42) {
printf("FAIL: neg\n");
ok = 0;
}
if (test_negw(100) != -100) {
printf("FAIL: negw\n");
ok = 0;
}
if (test_sextw(0x80000000) != 0xffffffff80000000LL) {
printf("FAIL: sext.w\n");
ok = 0;
}
if (test_fmv_s(3.14f) != 3.14f) {
printf("FAIL: fmv.s\n");
ok = 0;
}
if (test_fneg_s(3.14f) != -3.14f) {
printf("FAIL: fneg.s\n");
ok = 0;
}
if (test_fmv_d(2.718281828) != 2.718281828) {
printf("FAIL: fmv.d\n");
ok = 0;
}
if (test_fneg_d(2.718281828) != -2.718281828) {
printf("FAIL: fneg.d\n");
ok = 0;
}
printf("%s\n", ok ? "PASS" : "FAIL");
return ok ? 0 : 1;
}
#else
int main(void)
{
printf("SKIP\n");
return 0;
}
#endif

View File

@ -0,0 +1 @@
PASS