From a64353ce71f68b0386011d42060059aac5c8a8e3 Mon Sep 17 00:00:00 2001 From: grischka Date: Mon, 23 Sep 2019 17:45:39 +0200 Subject: [PATCH] tccgen.c: generic char/short promotion for function return values --- arm64-gen.c | 6 +----- i386-gen.c | 28 ---------------------------- tccgen.c | 6 ++++++ tests/tcctest.c | 4 ++++ x86_64-gen.c | 35 +---------------------------------- 5 files changed, 12 insertions(+), 67 deletions(-) diff --git a/arm64-gen.c b/arm64-gen.c index da54b3d7..5ea47db4 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -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; diff --git a/i386-gen.c b/i386-gen.c index 47568b6e..8b81c66f 100644 --- a/i386-gen.c +++ b/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 }; diff --git a/tccgen.c b/tccgen.c index 43c142b2..0475b3c5 100644 --- a/tccgen.c +++ b/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(); diff --git a/tests/tcctest.c b/tests/tcctest.c index 0c28d316..3333e878 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -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; } diff --git a/x86_64-gen.c b/x86_64-gen.c index 5d42f195..fd2d6936 100644 --- a/x86_64-gen.c +++ b/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) {