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 | ST_FUNC void gen_cvt_sxtw(void) | 1269 | ST_FUNC void gen_cvt_sxtw(void) |
| 1249 | { | 1270 | { |
| 1250 | /* XXX on risc-v the registers are usually sign-extended already. | 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 | /* ------------ riscv64-gen.c ------------ */ | 1725 | /* ------------ riscv64-gen.c ------------ */ |
| 1726 | #ifdef TCC_TARGET_RISCV64 | 1726 | #ifdef TCC_TARGET_RISCV64 |
| 1727 | ST_FUNC void gen_opl(int op); | 1727 | ST_FUNC void gen_opl(int op); |
| 1728 | //ST_FUNC void gfunc_return(CType *func_type); | ||
| 1729 | ST_FUNC void gen_va_start(void); | 1728 | ST_FUNC void gen_va_start(void); |
| 1730 | ST_FUNC void arch_transfer_ret_regs(int); | 1729 | ST_FUNC void arch_transfer_ret_regs(int); |
| 1731 | ST_FUNC void gen_cvt_sxtw(void); | 1730 | ST_FUNC void gen_cvt_sxtw(void); |
| 1731 | ST_FUNC void gen_cvt_csti(int t); | ||
| 1732 | ST_FUNC void gen_increment_tcov (SValue *sv); | 1732 | ST_FUNC void gen_increment_tcov (SValue *sv); |
| 1733 | #endif | 1733 | #endif |
| 1734 | 1734 | ||
| @@ -3471,11 +3471,11 @@ error: · 3470 unmodified lines | |||
| 3471 | 3471 | ||
| 3472 | if (ds >= ss) | 3472 | if (ds >= ss) |
| 3473 | goto done; | 3473 | goto done; |
| 3474 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 | 3474 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 |
| 3475 | if (ss == 4) { | 3475 | if (ss == 4) { |
| 3476 | gen_cvt_csti(dbt); | 3476 | gen_cvt_csti(dbt); |
| 3477 | goto done; | 3477 | goto done; |
| 3478 | } | 3478 | } |
| 3479 | #endif | 3479 | #endif |
| 3480 | bits = (ss - ds) * 8; | 3480 | bits = (ss - ds) * 8; |
| 3481 | /* for unsigned, gen_op will convert SAR to SHR */ | 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 | ||