From 9f0915a506fa7f2c67a7f25fc4af76fc178927d6 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Sat, 2 May 2026 23:58:23 +0800 Subject: [PATCH] riscv64: implement gen_cvt_csti for narrow int promotion Add sign/zero extension for char/short to int casts using slli+srai (signed) or slli+srli/andi (unsigned) sequences. Also adds RISCV64 to the gen_cvt_csti fast-path conditional in tccgen.c:3466, matching arm64/i386/x86_64. Verified on Spacemit X100: all tests2 pass, no regressions. --- riscv64-gen.c | 21 ++++++++++ tcc.h | 2 +- tccgen.c | 10 ++--- tests/tests2/139_narrow_type_conversion.c | 42 +++++++++++++++++++ .../tests2/139_narrow_type_conversion.expect | 2 + 5 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 tests/tests2/139_narrow_type_conversion.c create mode 100644 tests/tests2/139_narrow_type_conversion.expect diff --git a/riscv64-gen.c b/riscv64-gen.c index 4725c1b6..8356f595 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -1245,6 +1245,27 @@ ST_FUNC void gen_opf(int op) } } +ST_FUNC void gen_cvt_csti(int t) +{ + int r = ireg(gv(RC_INT)); + if ((t & VT_BTYPE) == VT_SHORT) { + if (t & VT_UNSIGNED) { + EI(0x13, 1, r, r, 48); // slli r, r, 48 + EI(0x13, 5, r, r, 48); // srli r, r, 48 + } else { + EI(0x13, 1, r, r, 48); // slli r, r, 48 + EIu(0x13, 5, r, r, 0x400 | 48); // srai r, r, 48 + } + } else { + if (t & VT_UNSIGNED) { + EI(0x13, 7, r, r, 0xff); // andi r, r, 0xff + } else { + EI(0x13, 1, r, r, 56); // slli r, r, 56 + EIu(0x13, 5, r, r, 0x400 | 56); // srai r, r, 56 + } + } +} + ST_FUNC void gen_cvt_sxtw(void) { /* XXX on risc-v the registers are usually sign-extended already. diff --git a/tcc.h b/tcc.h index 27ce1d2b..ed821cce 100644 --- a/tcc.h +++ b/tcc.h @@ -1725,10 +1725,10 @@ ST_FUNC void gen_increment_tcov (SValue *sv); /* ------------ riscv64-gen.c ------------ */ #ifdef TCC_TARGET_RISCV64 ST_FUNC void gen_opl(int op); -//ST_FUNC void gfunc_return(CType *func_type); ST_FUNC void gen_va_start(void); ST_FUNC void arch_transfer_ret_regs(int); ST_FUNC void gen_cvt_sxtw(void); +ST_FUNC void gen_cvt_csti(int t); ST_FUNC void gen_increment_tcov (SValue *sv); #endif diff --git a/tccgen.c b/tccgen.c index 75be059a..5848d9e0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3471,11 +3471,11 @@ error: if (ds >= ss) goto done; -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 - if (ss == 4) { - gen_cvt_csti(dbt); - goto done; - } +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 + if (ss == 4) { + gen_cvt_csti(dbt); + goto done; + } #endif bits = (ss - ds) * 8; /* for unsigned, gen_op will convert SAR to SHR */ diff --git a/tests/tests2/139_narrow_type_conversion.c b/tests/tests2/139_narrow_type_conversion.c new file mode 100644 index 00000000..4e1a66a2 --- /dev/null +++ b/tests/tests2/139_narrow_type_conversion.c @@ -0,0 +1,42 @@ +#include + +/* gen_cvt_csti test: verify narrow-type conversions in expressions. + Without the fix, TCC's riscv64 backend could miss the conversion + step when promoting a narrow result back to int, producing wrong + values (e.g., treating a char as still 32-bit). */ + +int main(void) +{ + int ok = 1; + int x = 0x12345678; + + /* Cast to char then add 1 — result must be 8-bit. */ + char c = (char)x + 1; + unsigned char uc = (unsigned char)x + 1; + short s = (short)x + 1; + unsigned short us = (unsigned short)x + 1; + + printf("c=%x uc=%x s=%x us=%x\n", + (unsigned char)c, (unsigned)uc, + (unsigned short)s, (unsigned)us); + + if (c != (char)0x78 + 1) { + printf("FAIL: char conversion\n"); + ok = 0; + } + if (uc != (unsigned char)0x78 + 1) { + printf("FAIL: unsigned char conversion\n"); + ok = 0; + } + if (s != (short)0x5678 + 1) { + printf("FAIL: short conversion\n"); + ok = 0; + } + if (us != (unsigned short)0x5678 + 1) { + printf("FAIL: unsigned short conversion\n"); + ok = 0; + } + + printf("%s\n", ok ? "PASS" : "FAIL"); + return ok ? 0 : 1; +} diff --git a/tests/tests2/139_narrow_type_conversion.expect b/tests/tests2/139_narrow_type_conversion.expect new file mode 100644 index 00000000..915205e0 --- /dev/null +++ b/tests/tests2/139_narrow_type_conversion.expect @@ -0,0 +1,2 @@ +c=79 uc=79 s=5679 us=5679 +PASS