From patchwork Tue Oct 2 13:38:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Fix PR54735 Date: Tue, 02 Oct 2012 03:38:51 -0000 From: Richard Guenther X-Patchwork-Id: 188524 Message-Id: To: gcc-patches@gcc.gnu.org This fixes PR54735 - a bad interaction of non-up-to-date virtual SSA form, update-SSA and cfg cleanup. Morale of the story: cfg cleanup can remove blocks and thus release SSA names - SSA update is rightfully confused when such released SSA name is still used at update time. The following patch fixes the case in question simply by making sure to run update-SSA before cfg cleanup. [eventually release_ssa_name could treat virtual operands the same as regular SSA names when they are scheduled for a re-write, that would make this whole mess more robust - I am thinking of this] Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2012-10-02 Richard Guenther PR middle-end/54735 * tree-ssa-pre.c (do_pre): Make sure to update virtual SSA form before cleaning up the CFG. * g++.dg/torture/pr54735.C: New testcase. Index: gcc/tree-ssa-pre.c =================================================================== --- gcc/tree-ssa-pre.c (revision 191969) +++ gcc/tree-ssa-pre.c (working copy) @@ -4820,6 +4820,13 @@ do_pre (void) free_scc_vn (); + /* Tail merging invalidates the virtual SSA web, together with + cfg-cleanup opportunities exposed by PRE this will wreck the + SSA updating machinery. So make sure to run update-ssa + manually, before eventually scheduling cfg-cleanup as part of + the todo. */ + update_ssa (TODO_update_ssa_only_virtuals); + return todo; } @@ -4845,8 +4852,7 @@ struct gimple_opt_pass pass_pre = 0, /* properties_provided */ 0, /* properties_destroyed */ TODO_rebuild_alias, /* todo_flags_start */ - TODO_update_ssa_only_virtuals | TODO_ggc_collect - | TODO_verify_ssa /* todo_flags_finish */ + TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ } }; Index: gcc/testsuite/g++.dg/torture/pr54735.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr54735.C (revision 0) +++ gcc/testsuite/g++.dg/torture/pr54735.C (working copy) @@ -0,0 +1,179 @@ +// { dg-do compile } + +class Gmpfr +{}; +class M : Gmpfr +{ +public: + Gmpfr infconst; + M(int); +}; +templatestruct A; +templateclass N; +templateclass O; +templatestruct B; +struct C +{ + enum + { value }; +}; +class D +{ +public: + enum + { ret }; +}; +struct F +{ + enum + { ret = 0 ? : 0 }; +}; +templatestruct G +{ + typedef Otype; +}; +struct H +{ + void operator * (); +}; +struct I +{ + enum + { RequireInitialization = C::value ? : 0, ReadCost }; +}; +templatestruct J +{ + enum + { ret = A::InnerStrideAtCompileTime }; +}; +templatestruct K +{ + enum + { ret = A::OuterStrideAtCompileTime }; +}; +templateclass P : H +{ +public: + using H::operator *; + typedef typename A::Scalar Scalar; + enum + { RowsAtCompileTime = + A::RowsAtCompileTime, ColsAtCompileTime = + A::ColsAtCompileTime, SizeAtCompileTime = + F::ret, MaxRowsAtCompileTime = + A::MaxRowsAtCompileTime, MaxColsAtCompileTime = + A::MaxColsAtCompileTime, MaxSizeAtCompileTime = + F::ret, Flags = + A::Flags ? : 0 ? : 0, CoeffReadCost = + A::CoeffReadCost, InnerStrideAtCompileTime = + J::ret, OuterStrideAtCompileTime = K::ret }; + B operator << (const Scalar&); +}; + +templateclass O : public P +{}; + +templateclass L +{ +public: + + int cols() + { + return _Cols; + } +}; +templateclass Q : public G::type +{ +public: + typedef typename G::type Base; + typedef typename A::Index Index; + typedef typename A::Scalar Scalar; + L m_storage; + Index cols() + { + return m_storage.cols(); + } + + Scalar& coeffRef(Index, + Index); +}; + +templatestruct A > +{ + typedef _Scalar Scalar; + typedef int Index; + enum + { RowsAtCompileTime, ColsAtCompileTime = + _Cols, MaxRowsAtCompileTime, MaxColsAtCompileTime, Flags = + D::ret, CoeffReadCost = + I::ReadCost, InnerStrideAtCompileTime, OuterStrideAtCompileTime = + 0 ? : 0 }; +}; +templateclass N : public Q > +{ +public: + Q Base; + templateN(const T0&, + const T1&); +}; +void +__assert_fail(int) +throw() __attribute__((__noreturn__)); +templatestruct B +{ + typedef typename XprType::Scalar Scalar; + typedef typename XprType::Index Index; + B(XprType & p1, const Scalar &) : m_xpr(p1), m_col(), + m_currentBlockRows(1) + {} B& operator, (const Scalar&) + { + Index a; + + if (m_col == m_xpr.cols()) + { + m_col = 0; + m_currentBlockRows = 1; + a && "Too " ? static_cast(0) : __assert_fail(0); + } + m_col < m_xpr.cols() + && "Too " ? static_cast(0) : __assert_fail(1); + m_currentBlockRows ? static_cast(0) : __assert_fail(4); + m_xpr.coeffRef(0, m_col++) = 0; + return *this; + } + ~B() + { + 1 + m_currentBlockRows && m_col + && "Too " ? static_cast(0) : __assert_fail(0); + } + + XprType& m_xpr; + Index m_col; + Index m_currentBlockRows; +}; + +templateBP< + Derived >::operator << (const Scalar&) +{ + return B(*static_cast(this), 0); +} + +templatevoid + check_() +{ + Nm(0, 0); + m << 0, 0, 0, 0; +} + +templatevoid check() +{ + check_(); +} + +int main() +{ + check(); +}