mirror of
https://github.com/mirror/tinycc.git
synced 2025-04-01 12:30:08 +08:00
Fix sub-int returns on x86-64 and i386
the ABIs (and other compilers) extend sub-int return values in the caller. TCC extends them in the callee. For compatibility with those other compilers we have extend them in the caller as well. That introduces a useless double extension in pure TCC-compiled code, but fixing that generally requires that the code generator of TCC would understand sub-int types. For the time being bite the bullet.
This commit is contained in:
parent
5f737fb4d3
commit
749d19d70b
@ -369,6 +369,7 @@ static void gcall_or_jmp(int is_jmp)
|
|||||||
rt = vtop->type.ref->type.t;
|
rt = vtop->type.ref->type.t;
|
||||||
switch (rt & VT_BTYPE) {
|
switch (rt & VT_BTYPE) {
|
||||||
case VT_BYTE:
|
case VT_BYTE:
|
||||||
|
case VT_BOOL:
|
||||||
if (rt & VT_UNSIGNED) {
|
if (rt & VT_UNSIGNED) {
|
||||||
o(0xc0b60f); /* movzx %al, %eax */
|
o(0xc0b60f); /* movzx %al, %eax */
|
||||||
}
|
}
|
||||||
|
19
x86_64-gen.c
19
x86_64-gen.c
@ -920,7 +920,7 @@ void gfunc_call(int nb_args)
|
|||||||
|
|
||||||
/* other compilers don't clear the upper bits when returning char/short */
|
/* other compilers don't clear the upper bits when returning char/short */
|
||||||
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
|
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
if (bt == (VT_BYTE | VT_UNSIGNED))
|
if (bt == (VT_BYTE | VT_UNSIGNED) || (bt & VT_TYPE) == VT_BOOL)
|
||||||
o(0xc0b60f); /* movzbl %al, %eax */
|
o(0xc0b60f); /* movzbl %al, %eax */
|
||||||
else if (bt == VT_BYTE)
|
else if (bt == VT_BYTE)
|
||||||
o(0xc0be0f); /* movsbl %al, %eax */
|
o(0xc0be0f); /* movsbl %al, %eax */
|
||||||
@ -1230,7 +1230,7 @@ void gfunc_call(int nb_args)
|
|||||||
{
|
{
|
||||||
X86_64_Mode mode;
|
X86_64_Mode mode;
|
||||||
CType type;
|
CType type;
|
||||||
int size, align, r, args_size, stack_adjust, i, reg_count;
|
int size, align, r, args_size, stack_adjust, i, reg_count, bt;
|
||||||
int nb_reg_args = 0;
|
int nb_reg_args = 0;
|
||||||
int nb_sse_args = 0;
|
int nb_sse_args = 0;
|
||||||
int sse_reg, gen_reg;
|
int sse_reg, gen_reg;
|
||||||
@ -1413,6 +1413,21 @@ void gfunc_call(int nb_args)
|
|||||||
gcall_or_jmp(0);
|
gcall_or_jmp(0);
|
||||||
if (args_size)
|
if (args_size)
|
||||||
gadd_sp(args_size);
|
gadd_sp(args_size);
|
||||||
|
/* other compilers don't clear the upper bits when returning char/short,
|
||||||
|
TCC does so for convenience. When we'd stay purely within TCC compiled
|
||||||
|
code we wouldn't need this, but for compatibility we have to extend.
|
||||||
|
Ideally TCC wouldn't extend at return statements to not do double
|
||||||
|
extensions, or would understand sub-int types during expression
|
||||||
|
evaluation. */
|
||||||
|
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
|
if (bt == (VT_BYTE | VT_UNSIGNED) || (bt & VT_TYPE) == VT_BOOL)
|
||||||
|
o(0xc0b60f); /* movzbl %al, %eax */
|
||||||
|
else if (bt == VT_BYTE)
|
||||||
|
o(0xc0be0f); /* movsbl %al, %eax */
|
||||||
|
else if (bt == VT_SHORT)
|
||||||
|
o(0x98); /* cwtl */
|
||||||
|
else if (bt == (VT_SHORT | VT_UNSIGNED))
|
||||||
|
o(0xc0b70f); /* movzwl %al, %eax */
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user