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. I'm waiting until I committed the fix for PR69352. Richard. 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" } }