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).
Unified · Split
| @@ -1268,8 +1268,8 @@ ST_FUNC void gen_cvt_csti(int t) · 1267 unmodified lines | ||
| 1268 | 1268 | |
| 1269 | 1269 | ST_FUNC void gen_cvt_sxtw(void) |
| 1270 | 1270 | { |
| 1271 | − /* XXX on risc-v the registers are usually sign-extended already. | |
| 1272 | − Let's try to not do anything here. */ | |
| 1271 | + int r = ireg(gv(RC_INT)); | |
| 1272 | + EI(0x1b, 0, r, r, 0); // addiw r, r, 0 | |
| 1273 | 1273 | } |
| 1274 | 1274 | |
| 1275 | 1275 | ST_FUNC void gen_cvt_itof(int t) |
| @@ -0,0 +1,43 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | + | |
| 3 | +/* gen_cvt_sxtw test: verify sign-extension from 32-bit int to 64-bit long long. | |
| 4 | + Without the fix, the riscv64 backend had an empty stub for gen_cvt_sxtw, | |
| 5 | + leaving upper 32 bits unmodified (containing whatever was in the register | |
| 6 | + before), so (long long)(int)x produced wrong results for negative values. */ | |
| 7 | + | |
| 8 | +int main(void) | |
| 9 | +{ | |
| 10 | + int ok = 1; | |
| 11 | + int x = 0x80000000; | |
| 12 | + long long y = (long long)x; | |
| 13 | + | |
| 14 | + printf("y=%llx\n", (unsigned long long)y); | |
| 15 | + | |
| 16 | + if (y != 0xffffffff80000000LL) { | |
| 17 | + printf("FAIL: int→long long sign-extension\n"); | |
| 18 | + ok = 0; | |
| 19 | + } | |
| 20 | + | |
| 21 | + /* Also test positive value. */ | |
| 22 | + x = 0x40000000; | |
| 23 | + y = (long long)x; | |
| 24 | + printf("y=%llx\n", (unsigned long long)y); | |
| 25 | + | |
| 26 | + if (y != 0x40000000LL) { | |
| 27 | + printf("FAIL: int→long long positive value\n"); | |
| 28 | + ok = 0; | |
| 29 | + } | |
| 30 | + | |
| 31 | + /* Test via unsigned int to catch zero-extension vs sign-extension. */ | |
| 32 | + unsigned int ux = 0x80000000; | |
| 33 | + long long uy = (long long)(int)ux; | |
| 34 | + printf("uy=%llx\n", (unsigned long long)uy); | |
| 35 | + | |
| 36 | + if (uy != 0xffffffff80000000LL) { | |
| 37 | + printf("FAIL: unsigned→int→long long sign-extension\n"); | |
| 38 | + ok = 0; | |
| 39 | + } | |
| 40 | + | |
| 41 | + printf("%s\n", ok ? "PASS" : "FAIL"); | |
| 42 | + return ok ? 0 : 1; | |
| 43 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +y=ffffffff80000000 | |
| 2 | +y=40000000 | |
| 3 | +uy=ffffffff80000000 | |
| 4 | +PASS | |