On powerpc64-linux, with this testcase int f (_Complex double a) { extern _Complex double cd; return memcmp (&a, &cd, sizeof (a)); } I'm hitting this assert in expand_expr_addr_expr_1 /* If the DECL isn't in memory, then the DECL wasn't properly marked TREE_ADDRESSABLE, which will be either a front-end or a tree optimizer bug. */ gcc_assert (GET_CODE (result) == MEM); The decl rtl is: (concat:DC (mem/i:DF (reg/f:DI 113 virtual-incoming-args) [0 a+0 S8 A64]) (reg/v:DF 119 [ a+8 ])) That's buggy. We shouldn't have part of the concat in memory, and part in a reg. Fixed with: * function.c (split_complex_args): Copy TREE_ADDRESSABLE for synthetic decl. With that, we get (concat:DC (mem/i:DF (reg/f:DI 113 virtual-incoming-args) [0 a+0 S8 A64]) (mem/i:DF (plus:DI (reg/f:DI 113 virtual-incoming-args) (const_int 8 [0x8])) [0 D.1119+0 S8 A64])) Now I'm not sure where this should be fixed. I'm guessing that the hack I have in my local tree in expand_expr_addr_expr_1 to look inside the CONCAT isn't the right place to fix this. Also there's a much worse problem; The two pieces of the concat might not be adjacent. Consider int g (_Complex float a) { extern _Complex float cf; return memcmp (&a, &cf, sizeof (a)); } For this, the decl rtl is now (concat:SC (mem/i:SF (reg/f:DI 113 virtual-incoming-args) [0 a+0 S4 A64]) (mem/i:SF (plus:DI (reg/f:DI 113 virtual-incoming-args) (const_int 8 [0x8])) [0 D.1128+0 S4 A64])) Notice that the two mems are 8 bytes apart but a _Complex float in memory should have the two 4 byte parts adjacent. Index: gcc/function.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/function.c,v retrieving revision 1.592 diff -u -p -r1.592 function.c --- gcc/function.c 1 Dec 2004 18:13:30 -0000 1.592 +++ gcc/function.c 9 Dec 2004 00:48:12 -0000 @@ -2061,6 +2061,7 @@ split_complex_args (tree args) /* Build a second synthetic decl. */ decl = build_decl (PARM_DECL, NULL_TREE, subtype); DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p); + TREE_ADDRESSABLE (decl) = TREE_ADDRESSABLE (p); layout_decl (decl, 0); /* Splice it in; skip the new decl. */
Created attachment 7709 [details] testcase
Fixing assign_parms_unsplit_complex
I think the correct solution is to explicitly *clear* TREE_ADDRESSABLE in split_complex_args and set DECL_ARTIFICIAL so that the two pieces get allocated to pseudo registers. Then unsplit_complex needs to notice that the original decl is TREE_ADDRESSABLE, allocate contiguous memory, and store the two pseudos into it. Something to work on for 4.1 might be noticing that the two members of the concat live in adjacent parameter memory, and promote that parameter memory to the address of the entire complex. That wouldn't be particularly easy at the stage that unsplit_complex is currently called.
http://gcc.gnu.org/ml/gcc-patches/2004-12/msg00682.html
Subject: Bug 18896 CVSROOT: /cvs/gcc Module name: gcc Changes by: amodra@gcc.gnu.org 2004-12-23 00:10:50 Modified files: gcc : ChangeLog function.c Log message: PR target/18896 * function.c (split_complex_args): Set DECL_ARTIFICIAL and DECL_IGNORED_P for real and imaginary parts if the parm is addressable. (assign_parms_unsplit_complex): If parm addressable, save real and imaginary parts to a stack temp. Pass assign_parm_data_all. (assign_parms): Adjust assign_parms_unsplit_complex call. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.6924&r2=2.6925 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/function.c.diff?cvsroot=gcc&r1=1.595&r2=1.596
Fixed mainline. gcc-3.4 not affected by this particular problem.