mirror of
https://github.com/frida/tinycc
synced 2025-02-08 03:14:02 +03:00
tccgen.c: generic char/short promotion for function return values
This commit is contained in:
parent
89372dc482
commit
a64353ce71
@ -959,11 +959,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
{
|
||||
int rt = return_type->t;
|
||||
int bt = rt & VT_BTYPE;
|
||||
if (bt == VT_BYTE || bt == VT_SHORT)
|
||||
// Promote small integers:
|
||||
o(0x13001c00 | (bt == VT_SHORT) << 13 |
|
||||
(uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
|
||||
else if (bt == VT_STRUCT && !(a[0] & 1)) {
|
||||
if (bt == VT_STRUCT && !(a[0] & 1)) {
|
||||
// A struct was returned in registers, so write it out:
|
||||
gv(RC_R(8));
|
||||
--vtop;
|
||||
|
28
i386-gen.c
28
i386-gen.c
@ -357,34 +357,6 @@ static void gcall_or_jmp(int is_jmp)
|
||||
o(0xff); /* call/jmp *r */
|
||||
o(0xd0 + r + (is_jmp << 4));
|
||||
}
|
||||
if (!is_jmp) {
|
||||
int rt;
|
||||
/* extend the return value to the whole register if necessary
|
||||
visual studio and gcc do not always set the whole eax register
|
||||
when assigning the return value of a function */
|
||||
rt = vtop->type.ref->type.t;
|
||||
switch (rt & VT_BTYPE) {
|
||||
case VT_BYTE:
|
||||
case VT_BOOL:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b60f); /* movzx %al, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0be0f); /* movsx %al, %eax */
|
||||
}
|
||||
break;
|
||||
case VT_SHORT:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b70f); /* movzx %ax, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0bf0f); /* movsx %ax, %eax */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
|
6
tccgen.c
6
tccgen.c
@ -5629,6 +5629,12 @@ special_math_val:
|
||||
}
|
||||
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
||||
}
|
||||
|
||||
/* Promote char/short return values. This is matters only
|
||||
for calling function that were not compiled by TCC */
|
||||
t = s->type.t & VT_BTYPE;
|
||||
if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL)
|
||||
vtop->r |= BFVAL(VT_MUSTCAST, 1);
|
||||
}
|
||||
if (s->f.func_noreturn)
|
||||
CODE_OFF();
|
||||
|
@ -3316,6 +3316,9 @@ void override_func2 (void)
|
||||
extern int bug_table[] __attribute__((section("__bug_table")));
|
||||
char * get_asm_string (void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
char *str = "(not tested)";
|
||||
#else
|
||||
extern int some_symbol;
|
||||
asm volatile (".globl some_symbol\n"
|
||||
"jmp .+6\n"
|
||||
@ -3330,6 +3333,7 @@ char * get_asm_string (void)
|
||||
"2:\t.long 1b - 2b, %c0 - 2b\n"
|
||||
".popsection\n" : : "i" ("A string"));
|
||||
char * str = ((char*)bug_table) + bug_table[1];
|
||||
#endif
|
||||
return str;
|
||||
}
|
||||
|
||||
|
35
x86_64-gen.c
35
x86_64-gen.c
@ -902,23 +902,6 @@ void gfunc_call(int nb_args)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* other compilers don't clear the upper bits when returning char/short */
|
||||
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); /* movzbl %al, %eax */
|
||||
#if 0 /* handled in gen_cast() */
|
||||
else if (bt == VT_INT)
|
||||
o(0x9848); /* cltq */
|
||||
else if (bt == (VT_INT | VT_UNSIGNED))
|
||||
o(0xc089); /* mov %eax,%eax */
|
||||
#endif
|
||||
vtop--;
|
||||
}
|
||||
|
||||
@ -1278,7 +1261,7 @@ void gfunc_call(int nb_args)
|
||||
{
|
||||
X86_64_Mode mode;
|
||||
CType type;
|
||||
int size, align, r, args_size, stack_adjust, i, reg_count, bt;
|
||||
int size, align, r, args_size, stack_adjust, i, reg_count;
|
||||
int nb_reg_args = 0;
|
||||
int nb_sse_args = 0;
|
||||
int sse_reg, gen_reg;
|
||||
@ -1466,25 +1449,9 @@ void gfunc_call(int nb_args)
|
||||
gcall_or_jmp(0);
|
||||
if (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--;
|
||||
}
|
||||
|
||||
|
||||
#define FUNC_PROLOG_SIZE 11
|
||||
|
||||
static void push_arg_reg(int i) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user