extern void abort (void);

_Complex v = 3.0 + 1.0iF;

void
foo (_Complex z, int *x)
{
  if (z != v)
    abort ();
}

_Complex bar (_Complex z) __attribute__ ((pure));
_Complex
bar (_Complex z)
{
  return v;
}

int
baz (void)
{
  int a, i;
  for (i = 0; i < 6; i++)
    foo (bar (1.0iF * i), &a);
  return 0;
}

int
main ()
{
  baz ();
  return 0;
}

is miscompiled at -O1 -m32 or -O2 -m32.

This was fixed in 4.2 and on the trunk with PR25505 changes (the tree-nrv.c
change most importantly), NRV in this case is really a wrong thing to do,
as target is _Complex at virtual-outgoing-regs, but those are also used
for the call.  Furthermore GCC then incorrectly computes where the region
actually was:
(insn 26 25 27 2 (set (mem/i:DF (plus:SI (reg/f:SI 56 virtual-outgoing-args)
                (const_int 4 [0x4])) [0 S8 A32])
        (float_extend:DF (reg:SF 69))) -1 (nil)
    (nil))

(insn 27 26 28 2 (set (mem/i:DF (plus:SI (reg/f:SI 56 virtual-outgoing-args)
                (const_int 12 [0xc])) [0 S8 A32])
        (reg:DF 68)) -1 (nil)
    (nil))

(insn 28 27 29 2 (set (mem:SI (reg/f:SI 56 virtual-outgoing-args) [0 S4 A32])
        (reg/f:SI 56 virtual-outgoing-args)) -1 (nil)
    (nil))

(call_insn 29 28 30 2 (parallel [
            (call (mem:QI (symbol_ref:SI ("bar") [flags 0x3] <function_decl
0x2aaaaea20400 bar>) [0 S1 A8])
                (const_int 20 [0x14]))
            (set (reg/f:SI 7 sp)
                (plus:SI (reg/f:SI 7 sp)
                    (const_int 4 [0x4])))
        ]) -1 (nil)
    (expr_list:REG_EH_REGION (const_int 0 [0x0])
        (nil))
    (nil))

(insn 30 29 31 2 (parallel [
            (set (reg/f:SI 7 sp)
                (plus:SI (reg/f:SI 7 sp)
                    (const_int -4 [0xfffffffffffffffc])))
            (clobber (reg:CC 17 flags))
        ]) -1 (nil)
    (nil))

(insn 31 30 32 2 (set (reg:DF 70)
        (mem/c/i:DF (plus:SI (reg/f:SI 54 virtual-stack-vars)
                (const_int -32 [0xffffffffffffffe0])) [2 S8 A64])) -1 (nil)
    (nil))

(insn 32 31 33 2 (set (mem:DF (plus:SI (reg/f:SI 56 virtual-outgoing-args)
                (const_int 4 [0x4])) [0 S8 A8])
        (reg:DF 70)) -1 (nil)
    (nil))

(insn 33 32 34 2 (set (reg:DF 71)
        (mem/c/i:DF (plus:SI (reg/f:SI 54 virtual-stack-vars)
                (const_int -24 [0xffffffffffffffe8])) [2 S8 A64])) -1 (nil)
    (nil))

(insn 34 33 35 2 (set (mem:DF (plus:SI (reg/f:SI 56 virtual-outgoing-args)
                (const_int 12 [0xc])) [0 S8 A8])
        (reg:DF 71)) -1 (nil)
    (nil))

So, it stores the return value to %esp (== %ebp - 68 at that point) and
loads from %ebp - 40.


-- 
           Summary: [4.1 Regression] Miscompilation with pure _Complex
                    returning call inside another fn's argument list
           Product: gcc
           Version: 4.1.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jakub at gcc dot gnu dot org
GCC target triplet: i686-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32285

Reply via email to