[Bug libstdc++/77686] [6/7 Regression] wrong code on arm-linux-gnueabi and arm-linux-gnueabihf

rguenth at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Tue Sep 27 09:10:00 GMT 2016


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77686

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jwakely.gcc at gmail dot com
          Component|target                      |libstdc++

--- Comment #10 from Richard Biener <rguenth at gcc dot gnu.org> ---
So it's

@(insn:TI 21 24 15 (parallel [
@            (set (reg:SI 0 r0)
@                (mem/c:SI (reg/f:SI 3 r3 [120]) [23 MEM[(union _Any_data
&)&D.50945]+0 S4 A64]))
@            (set (reg:SI 1 r1)
@                (mem/c:SI (plus:SI (reg/f:SI 3 r3 [120])
@                        (const_int 4 [0x4])) [23 MEM[(union _Any_data
&)&D.50945]+4 S4 A32]))
@        ]) t.ii:1926 383 {*ldm2_}
@     (nil))
        ldm     r3, {r0, r1}    @ 21    *ldm2_  [length = 4]

vs.

@(insn:TI 17 25 18 (set (mem/f/c:SI (plus:SI (reg/f:SI 13 sp)
@                (const_int 32 [0x20])) [30 MEM[(struct __lambda1 *)&D.50945]+0
S4 A64])
@        (reg/f:SI 5 r5 [orig:114 this ] [114])) 630 {*arm_movsi_vfp}
@     (nil))
        str     r5, [sp, #32]   @ 17    *arm_movsi_vfp/6        [length = 4]
@(insn:TI 18 17 118 (set (mem/f/c:SI (plus:SI (reg/f:SI 13 sp)
@                (const_int 36 [0x24])) [30 MEM[(struct __lambda1 *)&D.50945 +
4B]+0 S4 A32])
@        (reg/f:SI 5 r5 [orig:114 this ] [114])) 630 {*arm_movsi_vfp}
@     (nil))
        str     r5, [sp, #36]   @ 18    *arm_movsi_vfp/6        [length = 4]

and obviously r3 == sp + 32 and thus this is a must-alias.  But the alias sets
are 30 vs. 23 here.

At RTL expansion time:

;; MEM[(struct __lambda1 *)&D.50945] = this_4(D);

(insn 17 16 0 (set (mem/f/c:SI (plus:SI (reg/f:SI 105 virtual-stack-vars)
                (const_int -16 [0xfffffffffffffff0])) [30 MEM[(struct __lambda1
*)&D.50945]+0 S4 A64])
        (reg/f:SI 114 [ this ])) -1
     (nil))

;; MEM[(struct __lambda1 *)&D.50945 + 4B] = this_4(D);

(insn 18 17 0 (set (mem/f/c:SI (plus:SI (reg/f:SI 105 virtual-stack-vars)
                (const_int -12 [0xfffffffffffffff4])) [30 MEM[(struct __lambda1
*)&D.50945 + 4B]+0 S4 A32])
        (reg/f:SI 114 [ this ])) -1
     (nil))

...

;; __tmp = MEM[(union _Any_data &)&D.50945];

(insn 19 18 20 (set (reg:SI 119)
        (plus:SI (reg/f:SI 105 virtual-stack-vars)
            (const_int -40 [0xffffffffffffffd8]))) t.ii:1926 -1
     (nil))

(insn 20 19 21 (set (reg:SI 120)
        (plus:SI (reg/f:SI 105 virtual-stack-vars)
            (const_int -16 [0xfffffffffffffff0]))) t.ii:1926 -1
     (nil))

(insn 21 20 22 (parallel [
            (set (reg:SI 0 r0)
                (mem/c:SI (reg:SI 120) [23 MEM[(union _Any_data &)&D.50945]+0
S4 A64]))
            (set (reg:SI 1 r1)
                (mem/c:SI (plus:SI (reg:SI 120)
                        (const_int 4 [0x4])) [23 MEM[(union _Any_data
&)&D.50945]+4 S4 A32]))
        ]) t.ii:1926 -1
     (nil))

(insn 22 21 0 (parallel [
            (set (mem/c:SI (reg:SI 119) [23 __tmp+0 S4 A64])
                (reg:SI 0 r0))
            (set (mem/c:SI (plus:SI (reg:SI 119)
                        (const_int 4 [0x4])) [23 __tmp+4 S4 A32])
                (reg:SI 1 r1))
        ]) t.ii:1926 -1
     (nil))


From GIMPLE with more context:

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  dummy_a = 1;
  std::__ostream_insert<char, std::char_traits<char> > (&cout, "", 0);
  MEM[(struct  &)&f] ={v} {CLOBBER};
  MEM[(struct  &)&f] ={v} {CLOBBER};
  MEM[(union _Any_data *)&f] = this_4(D);
  MEM[(union _Any_data *)&f + 4B] = &dummy_a;
  MEM[(struct  &)&D.50945] ={v} {CLOBBER};
  MEM[(struct  &)&D.50945] ={v} {CLOBBER};
  MEM[(struct __lambda1 *)&D.50945] = this_4(D);          <---
  MEM[(struct __lambda1 *)&D.50945 + 4B] = this_4(D);     <---
  __tmp = MEM[(union _Any_data &)&D.50945];               <---
  MEM[(union _Any_data *)&D.50945] = MEM[(union _Any_data &)&f];
  MEM[(union _Any_data *)&f] = __tmp;
  __tmp ={v} {CLOBBER};
...

not very well optimized either, the copy to __tmp could be elided.

What SRA does is obviously correct now (and incorrect before):

-  MEM[(struct __lambda0 *)&D.47785] = __f;
+  MEM[(struct __lambda0 *)&D.47785] = __f$__this_17;
+  MEM[(struct __lambda0 *)&D.47785 + 4B] = __f$__dummy_a_19;
...

-  MEM[(struct __lambda1 *)&D.47815] = __f;
+  MEM[(struct __lambda1 *)&D.47815] = __f$__this_17;
+  MEM[(struct __lambda1 *)&D.47815 + 4B] = __f$__tmp_19;

so you see it now preserves the alias sets for the stores.

That _Any_data identifier makes me suspicious of the testcase invoking
undefined behavior:

  union _Any_data
  {
    void* _M_access() { return &_M_pod_data[0]; }
    const void* _M_access() const { return &_M_pod_data[0]; }
    template<typename _Tp>
      _Tp&
      _M_access()
      { return *static_cast<_Tp*>(_M_access()); }
    template<typename _Tp>
      const _Tp&
      _M_access() const
      { return *static_cast<const _Tp*>(_M_access()); }
    _Nocopy_types _M_unused;
    char _M_pod_data[sizeof(_Nocopy_types)];
  };

it seems to fall foul of the common misconception that you can do aggregate
copies of type _Any_data and that this will properly transfer objects
constructed into _Any_data::_M_pod_data.  That is obviously not the case.

-> latent libstd++ issue unless proved otherwise.


More information about the Gcc-bugs mailing list