/* { dg-do compile } */ /* { dg-options "-O2 -g -m32" } */ union U { unsigned long u; unsigned long long v; }; struct S { long s; long t; };
extern unsigned int foo (unsigned long long *, unsigned int); void bar (int x, union U y, struct S *z) { if ((x & 3) == 2) { unsigned long long r = y.v; unsigned int b = 1000000000L; unsigned int m; if ((r >> 32) == 0) { m = (unsigned int)r % b; r = (unsigned int)r / b; } else m = foo (&r, b); z->t = m; z->s = r; } } creates following bogus location description for y (which is passed by invisible reference on this arch). .byte 0x54 # DW_OP_reg4 .byte 0x93 # DW_OP_piece .byte 0x4 # uleb128 0x4 .byte 0x74 # DW_OP_breg4 .byte 0x4 # sleb128 4 .byte 0x93 # DW_OP_piece .byte 0x4 # uleb128 0x4 The 64-bit union is certainly not located partly in reg4 and partly in what reg4+4 points to, at least not in this case. The problem seems to be that GCC uses REG_EXPR y for the register that contains the address of the union: (reg:SI 4 4 [ y ]) and also (MEM_EXPR) for the MEM that actually contains it, e.g.: (mem/s:SI (reg:SI 4 4 [ y ]) [6 y+0 S4 A64]) (mem/s:SI (plus:SI (reg:SI 4 4 [ y ]) (const_int 4 [0x4])) [6 y+4 S4 A32]) The REG_EXPR on the register sounds wrong, if we allow REG_EXPR to not contain only decls, then it could be ADDR_EXPR <y>, otherwise perhaps nothing would be better than lying about where the argument is. -- Summary: REG_EXPR wrong for parameters passed by invisible reference Product: gcc Version: 4.0.1 Status: UNCONFIRMED Severity: normal Priority: P2 Component: debug AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: jakub at gcc dot gnu dot org CC: gcc-bugs at gcc dot gnu dot org,roland at redhat dot com GCC target triplet: ppc-linux http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21913