On Tue, Jan 19, 2016 at 10:08:17AM +0100, Richard Biener wrote: > > The following patch enhances the recent change to DOMs memory reference > value-numbering to cover PR69336 (all handled components instead of > just ones with outermost ARRAY_REF). > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
The new test case fails on s390x: -- snip -- void * D.35681; size_t n; const struct static_map cmap; const char * _4; int _5; int _11; void * _15; int _25; <bb 2>: cmap = *.LC3; _5 = cmap._values[0].second.first; if (_5 == 8) goto <bb 5>; else goto <bb 3>; <bb 3>: _25 = cmap._values[1].second.first; if (_25 == 8) goto <bb 5>; else goto <bb 4>; <bb 4>: _11 = cmap._values[2].second.first; if (_11 == 8) goto <bb 5>; else goto <bb 6>; <bb 5>: # n_8 = PHI <2(4), 0(2), 1(3)> _4 = MEM[(const char * const &)&cmap]._values[n_8].second.second; if (_4 == 0B) goto <bb 9>; else goto <bb 10>; <bb 6>: _15 = __cxa_allocate_exception (16); std::out_of_range::out_of_range (_15, "Key not found"); <bb 7>: __cxa_throw (_15, &_ZTISt12out_of_range, __comp_dtor ); <L6>: __cxa_free_exception (_15); _3 = __builtin_eh_pointer (5); __builtin_unwind_resume (_3); <bb 9>: abort (); <bb 10>: cmap ={v} {CLOBBER}; return 0; -- snip -- > 2016-01-19 Richard Biener <rguent...@suse.de> > > PR tree-optimization/69336 > * tree-ssa-scopedtables.c (avail_expr_hash): Handle all > handled components with get_ref_base_and_extent. > (equal_mem_array_ref_p): Adjust. > > * g++.dg/tree-ssa/pr69336.C: New testcase. > > Index: gcc/tree-ssa-scopedtables.c > =================================================================== > *** gcc/tree-ssa-scopedtables.c (revision 232508) > --- gcc/tree-ssa-scopedtables.c (working copy) > *************** avail_expr_hash (class expr_hash_elt *p) > *** 214,220 **** > { > /* T could potentially be a switch index or a goto dest. */ > tree t = expr->ops.single.rhs; > ! if (TREE_CODE (t) == MEM_REF || TREE_CODE (t) == ARRAY_REF) > { > /* Make equivalent statements of both these kinds hash together. > Dealing with both MEM_REF and ARRAY_REF allows us not to care > --- 214,220 ---- > { > /* T could potentially be a switch index or a goto dest. */ > tree t = expr->ops.single.rhs; > ! if (TREE_CODE (t) == MEM_REF || handled_component_p (t)) > { > /* Make equivalent statements of both these kinds hash together. > Dealing with both MEM_REF and ARRAY_REF allows us not to care > *************** avail_expr_hash (class expr_hash_elt *p) > *** 251,259 **** > static bool > equal_mem_array_ref_p (tree t0, tree t1) > { > ! if (TREE_CODE (t0) != MEM_REF && TREE_CODE (t0) != ARRAY_REF) > return false; > ! if (TREE_CODE (t1) != MEM_REF && TREE_CODE (t1) != ARRAY_REF) > return false; > > if (!types_compatible_p (TREE_TYPE (t0), TREE_TYPE (t1))) > --- 251,259 ---- > static bool > equal_mem_array_ref_p (tree t0, tree t1) > { > ! if (TREE_CODE (t0) != MEM_REF && ! handled_component_p (t0)) > return false; > ! if (TREE_CODE (t1) != MEM_REF && ! handled_component_p (t1)) > return false; > > if (!types_compatible_p (TREE_TYPE (t0), TREE_TYPE (t1))) > Index: gcc/testsuite/g++.dg/tree-ssa/pr69336.C > =================================================================== > *** gcc/testsuite/g++.dg/tree-ssa/pr69336.C (revision 0) > --- gcc/testsuite/g++.dg/tree-ssa/pr69336.C (working copy) > *************** > *** 0 **** > --- 1,86 ---- > + // { dg-do compile } > + // { dg-options "-O3 -fdump-tree-optimized -std=c++14" } > + > + #include <array> > + #include <utility> > + > + > + template<class Key, class T, size_t N> struct static_map > + { > + using key_type = Key; > + using mapped_type = T; > + using value_type = std::pair<const key_type, mapped_type>; > + private: > + using _value_type = std::pair<size_t, value_type>; > + _value_type _values[N]; > + static constexpr _value_type _new_value_type(const std::pair<Key, T> &v) > + { > + return std::make_pair(0, std::make_pair(v.first, v.second)); > + } > + public: > + template<class... U> constexpr static_map(U &&...il) : _values{ > _new_value_type(il)... } { } > + constexpr mapped_type &operator[](const key_type &k) { return at(k); } > + constexpr const mapped_type &operator[](const key_type &k) const { return > at(k); } > + constexpr mapped_type &at(const key_type &k) > + { > + for (size_t n = 0; n < N; n++) > + if (_values[n].second.first == k) > + return _values[n].second.second; > + throw std::out_of_range("Key not found"); > + } > + constexpr const mapped_type &at(const key_type &k) const > + { > + for (size_t n = 0; n < N; n++) > + if (_values[n].second.first == k) > + return _values[n].second.second; > + throw std::out_of_range("Key not found"); > + } > + }; > + namespace detail > + { > + template<class Key, class T, size_t N, size_t... I> constexpr > static_map<Key, T, N> static_map_from_array(const std::pair<Key, T>(&il)[N], > std::index_sequence<I...>) > + { > + return static_map<Key, T, N>(il[I]...); > + } > + } > + template<class Key, class T, size_t N> constexpr static_map<Key, T, N> > make_static_map(const std::pair<Key, T> (&il)[N]) > + { > + return detail::static_map_from_array<Key, T, N>(il, > std::make_index_sequence<N>()); > + } > + > + /* Two phase construction, required because heterogeneous braced init > + in C++ 14 has a big limitation: template<class... Args> auto make(Args > &&...) > + will accept make({ 5, "apple" }) as make(int, const char *) but > + make({ 5, "apple" }, { 8, "pear" }) will fail to deduce Args as a > + heterogeneous initializer_list is not permitted. This forces something > + like make(make_pair{ 5, "apple" }, make_pair{ 8, "pear" }, ...) which > + is less succinct than using a constexpr C array for the nested braced init. > + */ > + constexpr std::pair<const int, const char *> map_data[] = { > + { 5, "apple" }, > + { 8, "pear" }, > + { 0, "banana" } > + }; > + > + template<size_t N> constexpr int cstrcmp(const char *a, const char *b) > + { > + for (size_t n = 0; n < N; n++) > + { > + if (a[n] < b[n]) return -1; > + if (a[n] > b[n]) return 1; > + } > + return 0; > + } > + > + int main(void) > + { > + constexpr auto cmap = make_static_map(map_data); > + // No abort() appears in assembler, so this was executed constexpr > + if(!cmap[8]) abort(); > + // This however does cause code implementing a lookup to be generated, > + // so this was NOT executed constexpr > + //const char *foo=cmap[5]; > + return 0; > + } > + > + // { dg-final { scan-tree-dump-not "cmap" "optimized" } } Ciao Dominik ^_^ ^_^ -- Dominik Vogt IBM Germany