mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
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:
parent
2d17e5a6c4
commit
c8ca64d28b
@ -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 */
|
||||
/******************************************************/
|
||||
|
@ -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 */
|
||||
/******************************************************/
|
||||
|
12
tccgen.c
12
tccgen.c
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
/******************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user