On Tue, 6 Aug 2013, Gabriel Dos Reis wrote: > On Tue, Aug 6, 2013 at 1:46 PM, Nathan Sidwell <nat...@acm.org> wrote: > > Hi, > > i386elf.h defines: > > > > /* The ELF ABI for the i386 says that records and unions are returned > > in memory. */ > > > > #define SUBTARGET_RETURN_IN_MEMORY(TYPE, FNTYPE) \ > > (TYPE_MODE (TYPE) == BLKmode \ > > || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == > > 8)) > > > > and as such differs from the regular i86 return mechanism. Notice that the > > comment doesn't match the code: > > *) some structs/unions are non BLKmode > > *) some vectors can be BLKmode, some might not be -- the vector mode check > > appears to be an attempt to catch DImode vectors. > > > > Basing your ABI on the internal modes used by the compiler is not, IMHO, a > > sensible design choice. > > > > This code doesn't appear at first glance to cope with transparent_union. In > > fact it looks pretty bitrotted. > > > > Is it best just to junk the different behaviour at this point? > > Yes and yes :-)
This piece was introduced along i386elf.h itself at r28057 (1999-07-11) as: #define RETURN_IN_MEMORY(TYPE) \ (TYPE_MODE (TYPE) == BLKmode) while the corresponding i386.h piece was: #define RETURN_IN_MEMORY(TYPE) \ ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12) AFAICT at that time for the i386 target GCC only supported integer and x87 data types. The largest native (hardware) data type therefore was the x87 80-bit extended represented in C as a 12-byte `long double' type. For this and narrower types the two macros produce the same result. Also at that time IIUC all structs/unions were BLKmode. So the difference between the two macros only applied to complex types. The former would only put `float complex' data in registers (EDX:EAX) -- because that type fits in 8 bytes -- and any other results in memory. The latter however wanted to put all complex data in registers, including `double complex' (16 bytes) and `long double complex' (24 bytes). As observed by Nathan in: http://gcc.gnu.org/ml/gcc-patches/2013-08/msg00373.html this can't possibly work, as i386 only makes 3 GPRs possibly available (defined as call-clobbered) for results: EAX, EDX and ECX. Jeff, given the above -- do you happen to remember what made you make the i386/ELF target different from the base i386 target? Did I miss anything in the consideration above? The decision looks like has been deliberate, the i386.h default would normally apply (as i386elf.h included it at the beginning), but the macro was explicitly undefined and then defined as above. Of course even the decision made by the base i386 target to put `float complex' data in GPRs seems odd to me -- that's awkward and costly to handle as there's no way to pass such data between FPRs and GPRs without going through memory (so what's the point not to just leave it there?). And then this data is obviously useless in GPRs as it has to be put back to FPRs by the caller by the same long route if any further arithmetic is required. If in registers at all, I would expect complex results to be returned in ST(1):ST(0) -- that would make them accessible right away and the ABI consistent with real results returned in ST(0). Then, as further evolution, with the addition of MMX and SSE support at r34721 (2000-06-26) both macros were changed, to: #define RETURN_IN_MEMORY(TYPE) \ (TYPE_MODE (TYPE) == BLKmode \ || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8)) and: #define RETURN_IN_MEMORY(TYPE) \ ((TYPE_MODE (TYPE) == BLKmode) \ || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8) \ || (int_size_in_bytes (TYPE) > 12 && TYPE_MODE (TYPE) != TImode \ && ! VECTOR_MODE_P (TYPE_MODE (TYPE)))) respectively, which IIUC made MMX data returned in memory and SSE data in registers -- in both cases. Bernd, if you still remember: am I missing anything here? Especially the TImode piece is unobvious to me -- why would it matter for MMX/SSE? Neither supports 128-bit integers. From this point onwards no further changes were made to the version of RETURN_IN_MEMORY in i386elf.h. The version in i386.h was updated with r39693 (2001-02-14): #define RETURN_IN_MEMORY(TYPE) \ ((TYPE_MODE (TYPE) == BLKmode) \ || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8)\ || (int_size_in_bytes (TYPE) > 12 && TYPE_MODE (TYPE) != TImode \ && TYPE_MODE (TYPE) != TFmode && ! VECTOR_MODE_P (TYPE_MODE (TYPE)))) and then in r45726 (2001-09-21) factored out to ix86_return_in_memory: #define RETURN_IN_MEMORY(TYPE) \ ix86_return_in_memory (TYPE) -- which eventually evolved to its current form. My conclusion therefore is i386/ELF was not maintained, as far as the return convention is concerned, beyond r34721 and it looks to me like it should have been converted with r45726 to make use of ix86_return_in_memory just like generic i386, perhaps with a special exception for complex types (although as I noted above, this exception was probably a mistake from the beginning). Any thoughts? Maciej