Skip to content

Commit

Permalink
tccgen: fix casts using code from upstream
Browse files Browse the repository at this point in the history
We detected issues tcc-mob built with us was failing to compile code
like:

    unsigned long x = 0xcafecafe;

It was applying sign extension, producing a `x == 0xffffffffcafecafe`.
Instead, when built with GCC tcc-mob produced the proper
`x == 0xcafecafe`. This is because our casts are faulty in RISC-V
because it always sign-extends and we need to clear those high bits
after the sign-extension.

Proper compilation should produce this after the value is loaded:

    slli reg, reg, 0x20 // shift left 32 times
    srli reg, reg, 0x20 // and back

Meaning the highest 32 bits are cleared.

Our casts didn't detect the need for this, and many appearances of
integer constants in tcc-mob were miscompiled, producing future errors
in the chain: `load`, code generation, elf...

This commit backports the `gen_cast` function from tcc-mob and
manipulates the code around it to make it fit in our internals. It's not
superclean, but it should work.

* arm64-gen.c (gen_cvt_csti): New function for char to int conversion.
* i386-gen.c (gen_cvt_csti): Likewise.
* x86_64-gen.c (gen_cvt_csti): Likewise.
(gen_cvt_sxtw): New function for word sign-extension.
* tcc.h: Add them to headers.
* tccgen.c (gen_cast): Update from upstream.
(btype_size): Add function.
  • Loading branch information
ekaitz-zarraga committed Apr 22, 2024
1 parent ba83f0f commit 34f21bb
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 126 deletions.
10 changes: 10 additions & 0 deletions arm64-gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,16 @@ ST_FUNC void gen_cvt_sxtw(void)
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
}

/* char/short to int conversion */
ST_FUNC void gen_cvt_csti(int t)
{
int r = intr(gv(RC_INT));
o(0x13001c00
| ((t & VT_BTYPE) == VT_SHORT) << 13
| (uint32_t)!!(t & VT_UNSIGNED) << 30
| r | r << 5); // [su]xt[bh] w(r),w(r)
}

ST_FUNC void gen_cvt_itof(int t)
{
if (t == VT_LDOUBLE) {
Expand Down
13 changes: 13 additions & 0 deletions i386-gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,19 @@ ST_FUNC void gen_cvt_ftof(int t)
gv(RC_FLOAT);
}

/* char/short to int conversion */
ST_FUNC void gen_cvt_csti(int t)
{
int r, sz, xl;
r = gv(RC_INT);
sz = !(t & VT_UNSIGNED);
xl = (t & VT_BTYPE) == VT_SHORT;
o(0xc0b60f /* mov[sz] %a[xl], %eax */
| (sz << 3 | xl) << 8
| (r << 3 | r) << 16
);
}

/* computed goto support */
ST_FUNC void ggoto(void)
{
Expand Down
3 changes: 3 additions & 0 deletions tcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,7 @@ ST_FUNC void gen_le16(int c);
ST_FUNC void gen_le32(int c);
ST_FUNC void gen_addr32(int r, Sym *sym, long c);
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c);
ST_FUNC void gen_cvt_csti(int t);
#endif

#ifdef CONFIG_TCC_BCHECK
Expand All @@ -1573,6 +1574,7 @@ ST_FUNC void gen_bounded_ptr_deref(void);

/* ------------ x86_64-gen.c ------------ */
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
ST_FUNC void gen_opl(int op);
#endif
Expand All @@ -1589,6 +1591,7 @@ ST_FUNC void gen_cvt_itof1(int t);
/* ------------ arm64-gen.c ------------ */
#ifdef TCC_TARGET_ARM64
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_cvt_csti(int t);
ST_FUNC void gen_opl(int op);
ST_FUNC void gfunc_return(CType *func_type);
ST_FUNC void gen_va_start(void);
Expand Down

0 comments on commit 34f21bb

Please sign in to comment.