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 | ST_FUNC void gen_cvt_sxtw(void) | 1269 | ST_FUNC void gen_cvt_sxtw(void) |
| 1270 | { | 1270 | { |
| 1271 | /* XXX on risc-v the registers are usually sign-extended already. | 1271 | int r = ireg(gv(RC_INT)); |
| 1272 | Let's try to not do anything here. */ | 1272 | EI(0x1b, 0, r, r, 0); // addiw r, r, 0 |
| 1273 | } | 1273 | } |
| 1274 | 1274 | ||
| 1275 | ST_FUNC void gen_cvt_itof(int t) | 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 | ||