Adjust return value promotion for some archs

this is a bit complicated: for i386 and x86-64 we really need to
extend return values ourself, as the common code now does.  For arm64
this at least preserves old behaviour.  For riscv64 we don't have to
extend ourself but can expect things to be extended up to int (this
matters for var-args tests, when the sign-extension to int64 needs to
happen explicitely).  As the extensions are useless, don't do them.

And for arm32 we actually can't express GCC behaviour: the callee side
expects the return value to be correctly extended to int32, but
remembers the original type.  In case the ultimate target type for the
call result is only int, no further extension is done.  But in case
the target type is e.g. int64 an extension happens, but not from int32
but from the original type.  We don't know the ultimate target type,
so we have to choose a type to put into vtop:
* original type (plus VT_MUSTCAST) - this looses when the ultimate
  target is int (GCC: no cast, TCC: a cast)
* int (without MUSTCAST) - this looses when the ultimate target is
  int64 (GCC: cast from original type, TCC: cast from int)
This difference can only be seen with undefined sources, like the
testcases, so it doesn't seem worthwhile to try an make it work, just
disable the test on arm and choose the second variant as that generates
less code.
This commit is contained in:
Michael Matz 2019-12-17 01:46:06 +01:00
parent 2d17e5a6c4
commit c8ca64d28b
5 changed files with 26 additions and 10 deletions

View File

@ -40,6 +40,9 @@
#define CHAR_IS_UNSIGNED
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/

View File

@ -71,6 +71,10 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/

View File

@ -5631,10 +5631,18 @@ special_math_val:
}
/* Promote char/short return values. This is matters only
for calling function that were not compiled by TCC */
for calling function that were not compiled by TCC and
only on some architectures. For those where it doesn't
matter we expect things to be already promoted to int,
but not larger. */
t = s->type.t & VT_BTYPE;
if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL)
if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL) {
#ifdef PROMOTE_RET
vtop->r |= BFVAL(VT_MUSTCAST, 1);
#else
vtop->type.t = VT_INT;
#endif
}
}
if (s->f.func_noreturn)
CODE_OFF();

View File

@ -1210,13 +1210,7 @@ void struct_test()
/* simulate char/short return value with undefined upper bits */
static int __csf(int x) { return x; }
static void *_csf = __csf;
#ifdef __TINYC__
#define csf(t,n) ((t(*)(int))_csf)(n)
#define csfb csf
#else /* arm gcc maybe doesn't promote function return values */
#define csf(t,n) (t) n
#define csfb(t,n) (t) (n & 255)
#endif
/* XXX: depend on endianness */
void char_short_test()
@ -1257,14 +1251,18 @@ void char_short_test()
var4 = 0x11223344aa998877ULL;
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
printf("promote char/short cast VA %d %d\n", (char)(var1 + 1), (char)(var4 + 1));
#if !defined(__arm__)
/* We can't really express GCC behaviour of return type promotion in
the presence of undefined behaviour (like __csf is). */
var1 = csf(unsigned char,0x89898989);
var4 = csf(signed char,0xabababab);
printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
printf("promote char/short fumcret VA %d %d %d %d\n",
csf(unsigned short,0xcdcdcdcd),
csf(short,0xefefefef),
csfb(_Bool,0x33221100),
csfb(_Bool,0x33221101));
csf(_Bool,0x33221100),
csf(_Bool,0x33221101));
#endif
var3 = -10;
var1 = (char)(unsigned char)(var3 + 1);
var4 = (char)(unsigned char)(var3 + 1);

View File

@ -102,6 +102,9 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 16
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/