The compat/struct-return-19 testcase has been failing on ia64-hpux
(and I imagine all other ia64 targets as well) for some time. I have
tracked the problem to an improperly handled case in several parts of
the code generation for function calls.
On ia64, this structure
struct Ssds { struct Sd { double d; } sd; };
is passed in registers and returned in registers. Floating-point
registers. (It's a 'homogenous floating-point aggregate'.) GCC
emits code to load it into the appropriate floating point register for
both call and return, but it uses the wrong move instruction: the one
you're supposed to use to load an integer into a floating-point
register. (ldf8 instead of ldfd; setf.sig instead of setf.d; etc.)
This garbles the value.
The basic issue is that calls.c, expr.c, function.c, and ia64.c all
assume in various places that a BLKmode quantity is to be loaded into
a register, any register, using word_mode (DImode, in this case)
moves. This is wrong when loading a DFmode value into one of the
ia64's floating point registers; it's gotta be loaded as DFmode or it
will be mangled.
The simplest fix for this problem that I can find is to give the
structure type DFmode instead of BLKmode. This is the default
behavior, but it's being overridden in ia64/hpux.h by
MEMBER_TYPE_FORCES_BLK, which evaluates true for any nested structure
no matter what its contents. As far as I can tell, the point of that
definition is to get a structure containing a short integer to be
passed in the high half of the register as required for big-endian
IA64. (Y'all may puke now.) Giving BLKmode to the above structure is
unintentional. This can easily be corrected by having
MEMBER_TYPE_FORCES_BLK look only at its mode argument, and that is
what the patch does.
There is no PR for this failure but I would like to suggest it for 3.4
anyway since it fixes a calling-convention bug. (There are no ABI
consequences - it's passing the wrong value in the right place.) The
patch by definition cannot affect any target other than ia64-hpux.
Bootstrapped on ia64-hp-hpux11.23 (3.4 branch, C/C++ only) with no
regressions. OK mainline? 3.4 branch?