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.
This commit is contained in:
Meng Zhuo 2026-05-02 23:58:23 +08:00
parent 69c8e92566
commit 9f0915a506
5 changed files with 71 additions and 6 deletions

View File

@ -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.

2
tcc.h
View File

@ -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

View File

@ -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 */

View File

@ -0,0 +1,42 @@
#include <stdio.h>
/* 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;
}

View File

@ -0,0 +1,2 @@
c=79 uc=79 s=5679 us=5679
PASS