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.
Unified · Split
| @@ -1245,6 +1245,27 @@ ST_FUNC void gen_opf(int op) · 1244 unmodified lines | ||
| 1245 | 1245 | } |
| 1246 | 1246 | } |
| 1247 | 1247 | |
| 1248 | +ST_FUNC void gen_cvt_csti(int t) | |
| 1249 | +{ | |
| 1250 | + int r = ireg(gv(RC_INT)); | |
| 1251 | + if ((t & VT_BTYPE) == VT_SHORT) { | |
| 1252 | + if (t & VT_UNSIGNED) { | |
| 1253 | + EI(0x13, 1, r, r, 48); // slli r, r, 48 | |
| 1254 | + EI(0x13, 5, r, r, 48); // srli r, r, 48 | |
| 1255 | + } else { | |
| 1256 | + EI(0x13, 1, r, r, 48); // slli r, r, 48 | |
| 1257 | + EIu(0x13, 5, r, r, 0x400 | 48); // srai r, r, 48 | |
| 1258 | + } | |
| 1259 | + } else { | |
| 1260 | + if (t & VT_UNSIGNED) { | |
| 1261 | + EI(0x13, 7, r, r, 0xff); // andi r, r, 0xff | |
| 1262 | + } else { | |
| 1263 | + EI(0x13, 1, r, r, 56); // slli r, r, 56 | |
| 1264 | + EIu(0x13, 5, r, r, 0x400 | 56); // srai r, r, 56 | |
| 1265 | + } | |
| 1266 | + } | |
| 1267 | +} | |
| 1268 | + | |
| 1248 | 1269 | ST_FUNC void gen_cvt_sxtw(void) |
| 1249 | 1270 | { |
| 1250 | 1271 | /* XXX on risc-v the registers are usually sign-extended already. |
| @@ -1725,10 +1725,10 @@ ST_FUNC void gen_increment_tcov (SValue *sv); · 1724 unmodified lines | ||
| 1725 | 1725 | /* ------------ riscv64-gen.c ------------ */ |
| 1726 | 1726 | #ifdef TCC_TARGET_RISCV64 |
| 1727 | 1727 | ST_FUNC void gen_opl(int op); |
| 1728 | −//ST_FUNC void gfunc_return(CType *func_type); | |
| 1729 | 1728 | ST_FUNC void gen_va_start(void); |
| 1730 | 1729 | ST_FUNC void arch_transfer_ret_regs(int); |
| 1731 | 1730 | ST_FUNC void gen_cvt_sxtw(void); |
| 1731 | +ST_FUNC void gen_cvt_csti(int t); | |
| 1732 | 1732 | ST_FUNC void gen_increment_tcov (SValue *sv); |
| 1733 | 1733 | #endif |
| 1734 | 1734 | |
| @@ -3471,11 +3471,11 @@ error: · 3470 unmodified lines | ||
| 3471 | 3471 | |
| 3472 | 3472 | if (ds >= ss) |
| 3473 | 3473 | goto done; |
| 3474 | −#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 | |
| 3475 | − if (ss == 4) { | |
| 3476 | − gen_cvt_csti(dbt); | |
| 3477 | − goto done; | |
| 3478 | − } | |
| 3474 | +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 | |
| 3475 | + if (ss == 4) { | |
| 3476 | + gen_cvt_csti(dbt); | |
| 3477 | + goto done; | |
| 3478 | + } | |
| 3479 | 3479 | #endif |
| 3480 | 3480 | bits = (ss - ds) * 8; |
| 3481 | 3481 | /* for unsigned, gen_op will convert SAR to SHR */ |
| @@ -0,0 +1,42 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | + | |
| 3 | +/* gen_cvt_csti test: verify narrow-type conversions in expressions. | |
| 4 | + Without the fix, TCC's riscv64 backend could miss the conversion | |
| 5 | + step when promoting a narrow result back to int, producing wrong | |
| 6 | + values (e.g., treating a char as still 32-bit). */ | |
| 7 | + | |
| 8 | +int main(void) | |
| 9 | +{ | |
| 10 | + int ok = 1; | |
| 11 | + int x = 0x12345678; | |
| 12 | + | |
| 13 | + /* Cast to char then add 1 — result must be 8-bit. */ | |
| 14 | + char c = (char)x + 1; | |
| 15 | + unsigned char uc = (unsigned char)x + 1; | |
| 16 | + short s = (short)x + 1; | |
| 17 | + unsigned short us = (unsigned short)x + 1; | |
| 18 | + | |
| 19 | + printf("c=%x uc=%x s=%x us=%x\n", | |
| 20 | + (unsigned char)c, (unsigned)uc, | |
| 21 | + (unsigned short)s, (unsigned)us); | |
| 22 | + | |
| 23 | + if (c != (char)0x78 + 1) { | |
| 24 | + printf("FAIL: char conversion\n"); | |
| 25 | + ok = 0; | |
| 26 | + } | |
| 27 | + if (uc != (unsigned char)0x78 + 1) { | |
| 28 | + printf("FAIL: unsigned char conversion\n"); | |
| 29 | + ok = 0; | |
| 30 | + } | |
| 31 | + if (s != (short)0x5678 + 1) { | |
| 32 | + printf("FAIL: short conversion\n"); | |
| 33 | + ok = 0; | |
| 34 | + } | |
| 35 | + if (us != (unsigned short)0x5678 + 1) { | |
| 36 | + printf("FAIL: unsigned short conversion\n"); | |
| 37 | + ok = 0; | |
| 38 | + } | |
| 39 | + | |
| 40 | + printf("%s\n", ok ? "PASS" : "FAIL"); | |
| 41 | + return ok ? 0 : 1; | |
| 42 | +} | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +c=79 uc=79 s=5679 us=5679 | |
| 2 | +PASS | |