From ff917c09aac45d5e04b73b57a0fa0989acc65c59 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Sun, 3 May 2026 00:06:38 +0800 Subject: [PATCH] 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). --- riscv64-gen.c | 4 +- tests/tests2/140_int_sign_extension.c | 43 ++++++++++++++++++++++ tests/tests2/140_int_sign_extension.expect | 4 ++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/tests2/140_int_sign_extension.c create mode 100644 tests/tests2/140_int_sign_extension.expect diff --git a/riscv64-gen.c b/riscv64-gen.c index 8356f595..22789660 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -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) diff --git a/tests/tests2/140_int_sign_extension.c b/tests/tests2/140_int_sign_extension.c new file mode 100644 index 00000000..433a3e47 --- /dev/null +++ b/tests/tests2/140_int_sign_extension.c @@ -0,0 +1,43 @@ +#include + +/* 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; +} diff --git a/tests/tests2/140_int_sign_extension.expect b/tests/tests2/140_int_sign_extension.expect new file mode 100644 index 00000000..72a5df87 --- /dev/null +++ b/tests/tests2/140_int_sign_extension.expect @@ -0,0 +1,4 @@ +y=ffffffff80000000 +y=40000000 +uy=ffffffff80000000 +PASS