riscv64: implement gen_cvt_sxtw with addiw instruction

Replaces the empty stub that relied on 'RV64 registers are always
sign-extended' assumption.  Now emits addiw rd, rs, 0 for proper
32-to-64 bit sign extension, matching arm64's sxtw behavior.

Verified on Spacemit X100: tests2 pass (125_atomic_misc has a
pre-existing intermittent segfault, not caused by this change).
This commit is contained in:
Meng Zhuo 2026-05-03 00:06:38 +08:00
parent 9f0915a506
commit ff917c09aa
3 changed files with 49 additions and 2 deletions

View File

@ -1268,8 +1268,8 @@ ST_FUNC void gen_cvt_csti(int t)
ST_FUNC void gen_cvt_sxtw(void)
{
/* XXX on risc-v the registers are usually sign-extended already.
Let's try to not do anything here. */
int r = ireg(gv(RC_INT));
EI(0x1b, 0, r, r, 0); // addiw r, r, 0
}
ST_FUNC void gen_cvt_itof(int t)

View File

@ -0,0 +1,43 @@
#include <stdio.h>
/* gen_cvt_sxtw test: verify sign-extension from 32-bit int to 64-bit long long.
Without the fix, the riscv64 backend had an empty stub for gen_cvt_sxtw,
leaving upper 32 bits unmodified (containing whatever was in the register
before), so (long long)(int)x produced wrong results for negative values. */
int main(void)
{
int ok = 1;
int x = 0x80000000;
long long y = (long long)x;
printf("y=%llx\n", (unsigned long long)y);
if (y != 0xffffffff80000000LL) {
printf("FAIL: int→long long sign-extension\n");
ok = 0;
}
/* Also test positive value. */
x = 0x40000000;
y = (long long)x;
printf("y=%llx\n", (unsigned long long)y);
if (y != 0x40000000LL) {
printf("FAIL: int→long long positive value\n");
ok = 0;
}
/* Test via unsigned int to catch zero-extension vs sign-extension. */
unsigned int ux = 0x80000000;
long long uy = (long long)(int)ux;
printf("uy=%llx\n", (unsigned long long)uy);
if (uy != 0xffffffff80000000LL) {
printf("FAIL: unsigned→int→long long sign-extension\n");
ok = 0;
}
printf("%s\n", ok ? "PASS" : "FAIL");
return ok ? 0 : 1;
}

View File

@ -0,0 +1,4 @@
y=ffffffff80000000
y=40000000
uy=ffffffff80000000
PASS