https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127848
--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jakub Jelinek <[email protected]>: https://gcc.gnu.org/g:08c26561e4fe2cb6a26f5217673ed72c22d33e5b commit r17-5106-g08c26561e4fe2cb6a26f5217673ed72c22d33e5b Author: Jakub Jelinek <[email protected]> Date: Tue Oct 13 10:47:53 2026 +0200 tailc: Conservatively punt on some return type mismatches in tail call opt [PR127848] The first testcase is miscompiled on x86_64 and various other bitint_ext_undef targets, where the padding bits are unspecified. So, if callee returns unsigned _BitInt(15), only low 15 bits are specified, when caller returns unsigned short on x86_64, the bits 16-63 are unspecified, but bit 15 needs to be cleared, so we can't tail call. Now, tailc for casts currently checks TYPE_MODE differences and for the destination doesn't have non-mode precision (that one was added because of callee returning unsigned char and caller returning bool, those have the same mode but need to emit some code in between the call to the callee and return from caller). For useless_type_conversion_p we keep the distinction between normal INTEGER_TYPEs and BITINT_TYPE_P types with the same precision, because at function boundaries the target can have different calling convention. We don't really know at GIMPLE if the target returns unsigned _BitInt(16) and unsigned short the same way, there could be e.g. differences in padding bits etc. The following patch is a conservative fix, it punts on BITINT_TYPE_P != BITINT_TYPE_P conversions (exactly because we don't know if it changes ABI or not), and if both are BITINT_TYPE_P with the same TYPE_MODE, does some further checks - if TYPE_SIZE is different (and mode the same, that could be just BLKmode) it punts on TYPE_SIZE differences, for narrowing or same precision casts it punts except for bitint_ext_undef targets (on those the padding bits are unspecified and if we have more or same amount of unspecified padding bits it is ok), for widening casts it punts on the other side for all but bitint_ext_full targets (I'm not motivated enough to bother with figuring out all the details for bitint_ext_partial), because on those targets the narrower bitint has the bits already extended and if the narrower and wider _BitInt type have the same signedness, they are fine (now that I think about it, perhaps we could allow even narrower unsigned wider signed, can test that incrementally). In any case, the patch may pessimize code which would work just fine, callee returning unsigned _BitInt(16) and caller unsigned short or vice versa on many targets, etc. But, there can be multiple casts, so if we want to improve it, we could e.g. have casts where the callee type is compatible with the src_var type and dest type is compatible with the caller's type (so have these checks for intermediate calls but allow one cast from callee to caller return types), and then somehow deal with it during expansion (either in generic code try to expand code which converts the callee type temporary to caller type and check (and throw away) a sequence emitted by that whether it contains only normal moves and no other insns, or make sure every target verifies everything in their target hook). I don't have time to do that right now though and it might be too risky for backports anyway. 2026-10-13 Jakub Jelinek <[email protected]> PR middle-end/127848 * tree-tailcall.cc: Include target.h. (process_assignment): Punt if one of dest and src_var types is BITINT_TYPE_P and the other is not. If both are BITINT_TYPE_P, punt if TYPE_SIZE is different, or for narrowing or same precision conversions on != bitint_ext_undef targets, or for widening conversions on != bitint_ext_full targets or if signedness differs. * gcc.dg/pr127848-1.c: New test. * gcc.dg/pr127848-2.c: New test. * gcc.dg/pr127848-3.c: New test. * gcc.dg/pr127848-4.c: New test. * gcc.dg/pr127848-5.c: New test. Reviewed-by: Richard Biener <[email protected]>
