Message ID | 20110623195318.GD2736@virgil.arch.suse.de |
---|---|
State | New |
Headers | show |
On Thu, Jun 23, 2011 at 9:53 PM, Martin Jambor <mjambor@suse.cz> wrote: > Hi, > > When SRA tries to modify an assignment where on one side it should put > a new scalar replacement but the other is actually an aggregate with > a number of replacements for it, it will generate MEM-REFs into the > former replacement which can lead to miscompilations. > > This is avoided by the simple patch below. With it, we deal with > these situations like with other type-casts that SRA cannot handle: we > channel the data through the original variable and the original > statement. > > The testcase is not miscompiled with 4.6 gcc but the bug is just > latent there. > > I have verified the problem goes away on i686-linux. I have > bootstrapped and tested the patch on x86_64-linux too. I intend to do > a full i686 bootstrap and test but so far have not managed to do it. > > OK for trunk and 4.6 after it is unfrozen? Ok. Thanks, Richard. > Thanks, > > Martin > > > 2011-06-22 Martin Jambor <mjambor@suse.cz> > > PR tree-optimizations/49516 > * tree-sra.c (sra_modify_assign): Choose the safe path for > aggregate copies if we also did scalar replacements. > > * testsuite/g++.dg/tree-ssa/pr49516.C: New test. > > Index: src/gcc/tree-sra.c > =================================================================== > --- src.orig/gcc/tree-sra.c > +++ src/gcc/tree-sra.c > @@ -2804,7 +2804,8 @@ sra_modify_assign (gimple *stmt, gimple_ > there to do the copying and then load the scalar replacements of the LHS. > This is what the first branch does. */ > > - if (gimple_has_volatile_ops (*stmt) > + if (modify_this_stmt > + || gimple_has_volatile_ops (*stmt) > || contains_vce_or_bfcref_p (rhs) > || contains_vce_or_bfcref_p (lhs)) > { > Index: src/gcc/testsuite/g++.dg/tree-ssa/pr49516.C > =================================================================== > --- /dev/null > +++ src/gcc/testsuite/g++.dg/tree-ssa/pr49516.C > @@ -0,0 +1,86 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > + > +extern "C" void abort (void); > + > +typedef int int32; > +typedef unsigned int uint32; > +typedef unsigned long long uint64; > +typedef short int16; > + > +class Tp { > + public: > + Tp(int, const int segment, const int index) __attribute__((noinline)); > + > + inline bool operator==(const Tp& other) const; > + inline bool operator!=(const Tp& other) const; > + int GetType() const { return type_; } > + int GetSegment() const { return segment_; } > + int GetIndex() const { return index_; } > + private: > + inline static bool IsValidSegment(const int segment); > + static const int kSegmentBits = 28; > + static const int kTypeBits = 4; > + static const int kMaxSegment = (1 << kSegmentBits) - 1; > + > + union { > + > + struct { > + int32 index_; > + uint32 segment_ : kSegmentBits; > + uint32 type_ : kTypeBits; > + }; > + struct { > + int32 dummy_; > + uint32 type_and_segment_; > + }; > + uint64 value_; > + }; > +}; > + > +Tp::Tp(int t, const int segment, const int index) > + : index_(index), segment_(segment), type_(t) {} > + > +inline bool Tp::operator==(const Tp& other) const { > + return value_ == other.value_; > +} > +inline bool Tp::operator!=(const Tp& other) const { > + return value_ != other.value_; > +} > + > +class Range { > + public: > + inline Range(const Tp& position, const int count) __attribute__((always_inline)); > + inline Tp GetBeginTokenPosition() const; > + inline Tp GetEndTokenPosition() const; > + private: > + Tp position_; > + int count_; > + int16 begin_index_; > + int16 end_index_; > +}; > + > +inline Range::Range(const Tp& position, > + const int count) > + : position_(position), count_(count), begin_index_(0), end_index_(0) > + { } > + > +inline Tp Range::GetBeginTokenPosition() const { > + return position_; > +} > +inline Tp Range::GetEndTokenPosition() const { > + return Tp(position_.GetType(), position_.GetSegment(), > + position_.GetIndex() + count_); > +} > + > +int main () > +{ > + Range range(Tp(0, 0, 3), 0); > + if (!(range.GetBeginTokenPosition() == Tp(0, 0, 3))) > + abort (); > + > + if (!(range.GetEndTokenPosition() == Tp(0, 0, 3))) > + abort(); > + > + return 0; > +} >
Index: src/gcc/tree-sra.c =================================================================== --- src.orig/gcc/tree-sra.c +++ src/gcc/tree-sra.c @@ -2804,7 +2804,8 @@ sra_modify_assign (gimple *stmt, gimple_ there to do the copying and then load the scalar replacements of the LHS. This is what the first branch does. */ - if (gimple_has_volatile_ops (*stmt) + if (modify_this_stmt + || gimple_has_volatile_ops (*stmt) || contains_vce_or_bfcref_p (rhs) || contains_vce_or_bfcref_p (lhs)) { Index: src/gcc/testsuite/g++.dg/tree-ssa/pr49516.C =================================================================== --- /dev/null +++ src/gcc/testsuite/g++.dg/tree-ssa/pr49516.C @@ -0,0 +1,86 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +extern "C" void abort (void); + +typedef int int32; +typedef unsigned int uint32; +typedef unsigned long long uint64; +typedef short int16; + +class Tp { + public: + Tp(int, const int segment, const int index) __attribute__((noinline)); + + inline bool operator==(const Tp& other) const; + inline bool operator!=(const Tp& other) const; + int GetType() const { return type_; } + int GetSegment() const { return segment_; } + int GetIndex() const { return index_; } + private: + inline static bool IsValidSegment(const int segment); + static const int kSegmentBits = 28; + static const int kTypeBits = 4; + static const int kMaxSegment = (1 << kSegmentBits) - 1; + + union { + + struct { + int32 index_; + uint32 segment_ : kSegmentBits; + uint32 type_ : kTypeBits; + }; + struct { + int32 dummy_; + uint32 type_and_segment_; + }; + uint64 value_; + }; +}; + +Tp::Tp(int t, const int segment, const int index) + : index_(index), segment_(segment), type_(t) {} + +inline bool Tp::operator==(const Tp& other) const { + return value_ == other.value_; +} +inline bool Tp::operator!=(const Tp& other) const { + return value_ != other.value_; +} + +class Range { + public: + inline Range(const Tp& position, const int count) __attribute__((always_inline)); + inline Tp GetBeginTokenPosition() const; + inline Tp GetEndTokenPosition() const; + private: + Tp position_; + int count_; + int16 begin_index_; + int16 end_index_; +}; + +inline Range::Range(const Tp& position, + const int count) + : position_(position), count_(count), begin_index_(0), end_index_(0) + { } + +inline Tp Range::GetBeginTokenPosition() const { + return position_; +} +inline Tp Range::GetEndTokenPosition() const { + return Tp(position_.GetType(), position_.GetSegment(), + position_.GetIndex() + count_); +} + +int main () +{ + Range range(Tp(0, 0, 3), 0); + if (!(range.GetBeginTokenPosition() == Tp(0, 0, 3))) + abort (); + + if (!(range.GetEndTokenPosition() == Tp(0, 0, 3))) + abort(); + + return 0; +}