diff options
-rw-r--r-- | gcc/cgraph.cc | 2 | ||||
-rw-r--r-- | gcc/cp/call.cc | 15 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 9 | ||||
-rw-r--r-- | gcc/gimplify.cc | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/opt/icf1.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/opt/icf2.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/opt/icf3.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/array-temp1.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C | 1 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C | 13 | ||||
-rw-r--r-- | gcc/tree-core.h | 3 | ||||
-rw-r--r-- | gcc/tree.h | 6 | ||||
-rw-r--r-- | gcc/varasm.cc | 2 |
14 files changed, 104 insertions, 8 deletions
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index e8f9bec..e41e5ad 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -158,7 +158,7 @@ symtab_node::address_can_be_compared_p () flag_merge_constants permits us to assume the same on readonly vars. */ if (is_a <varpool_node *> (this) && (DECL_IN_CONSTANT_POOL (decl) - || (flag_merge_constants >= 2 + || ((flag_merge_constants >= 2 || DECL_MERGEABLE (decl)) && TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl)))) return false; return true; diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 2736f55..5d504e5 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4274,7 +4274,9 @@ maybe_init_list_as_array (tree elttype, tree init) init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST); tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init)); - return finish_compound_literal (arr, init, tf_none); + arr = finish_compound_literal (arr, init, tf_none); + DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true; + return arr; } /* If we were going to call e.g. vector(initializer_list<string>) starting @@ -8558,6 +8560,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST); array = build_array_of_n_type (elttype, len); array = finish_compound_literal (array, new_ctor, complain); + /* This is dubious now, should be blessed by P2752. */ + DECL_MERGEABLE (TARGET_EXPR_SLOT (array)) = true; /* Take the address explicitly rather than via decay_conversion to avoid the error about taking the address of a temporary. */ array = cp_build_addr_expr (array, complain); @@ -13571,8 +13575,13 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups, VAR. */ if (TREE_CODE (expr) != TARGET_EXPR) expr = get_target_expr (expr); - else if (TREE_ADDRESSABLE (expr)) - TREE_ADDRESSABLE (var) = 1; + else + { + if (TREE_ADDRESSABLE (expr)) + TREE_ADDRESSABLE (var) = 1; + if (DECL_MERGEABLE (TARGET_EXPR_SLOT (expr))) + DECL_MERGEABLE (var) = true; + } if (TREE_CODE (decl) == FIELD_DECL && extra_warnings && !warning_suppressed_p (decl)) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 19dfb3e..4d5e3f5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -5045,7 +5045,14 @@ handle_no_unique_addr_attribute (tree* node, int /*flags*/, bool* no_add_attrs) { - if (TREE_CODE (*node) != FIELD_DECL) + if (TREE_CODE (*node) == VAR_DECL) + { + DECL_MERGEABLE (*node) = true; + if (pedantic) + warning (OPT_Wattributes, "%qE attribute can only be applied to " + "non-static data members", name); + } + else if (TREE_CODE (*node) != FIELD_DECL) { warning (OPT_Wattributes, "%qE attribute can only be applied to " "non-static data members", name); diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index d0d16a2..bd5d0bf 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -5253,7 +5253,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && TREE_READONLY (object) && VAR_P (object) && !DECL_REGISTER (object) - && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object)) + && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object) + || DECL_MERGEABLE (object)) /* For ctors that have many repeated nonzero elements represented through RANGE_EXPRs, prefer initializing those through runtime loops over copies of large amounts diff --git a/gcc/testsuite/g++.dg/opt/icf1.C b/gcc/testsuite/g++.dg/opt/icf1.C new file mode 100644 index 0000000..fbb275e --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/icf1.C @@ -0,0 +1,16 @@ +// Test that -fipa-icf combines i and j. +// { dg-do run { target c++11 } } +// { dg-options -fipa-icf } + +[[no_unique_address]] extern const int i[] = { 1,2,3 }; +[[no_unique_address]] extern const int j[] = { 1,2,3 }; + +[[gnu::noipa]] void f (const void *a, const void *b) +{ + if (a != b) __builtin_abort(); +} + +int main() +{ + f (&i, &j); +} diff --git a/gcc/testsuite/g++.dg/opt/icf2.C b/gcc/testsuite/g++.dg/opt/icf2.C new file mode 100644 index 0000000..1ad48f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/icf2.C @@ -0,0 +1,17 @@ +// Test that -fipa-icf combines the backing arrays for a and b. +// { dg-do run { target c++11 } } +// { dg-options -fipa-icf } + +#include <initializer_list> + +[[gnu::noipa]] void f (const void *a, const void *b) +{ + if (a != b) __builtin_abort(); +} + +int main() +{ + auto a = { 1, 2 }; + auto b = { 1, 2 }; + f (a.begin(), b.begin()); +} diff --git a/gcc/testsuite/g++.dg/opt/icf3.C b/gcc/testsuite/g++.dg/opt/icf3.C new file mode 100644 index 0000000..8b86982 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/icf3.C @@ -0,0 +1,17 @@ +// Test that -fipa-icf combines the backing arrays for a and b. +// { dg-do run { target c++11 } } +// { dg-options -fipa-icf } + +#include <initializer_list> + +template <class T> +[[gnu::noipa]] void f (std::initializer_list<T> a, + std::initializer_list<T> b) +{ + if (a.begin() != b.begin()) __builtin_abort(); +} + +int main() +{ + f ({1,2}, {1,2}); +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C b/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C index 3df7aad..97c2e05 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C +++ b/gcc/testsuite/g++.dg/tree-ssa/array-temp1.C @@ -13,3 +13,9 @@ int f() using AR = const int[]; return AR{ 1,42,3,4,5,6,7,8,9,0 }[5]; } + +int g() +{ + std::initializer_list<int> a = {1,42,3}; + return a.begin()[0]; +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C index 053317b..b1d2d25 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C +++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C @@ -4,6 +4,7 @@ // Test that we do range-initialization from const char *. // { dg-final { scan-tree-dump {_M_range_initialize<const char\* const\*>} "gimple" } } +// { dg-final { scan-tree-dump {static const char.*72} "gimple" } } #include <string> #include <vector> diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C index c20713a..1e9ac73 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C +++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C @@ -4,6 +4,8 @@ // Test that we do range-initialization from const char *. // { dg-final { scan-tree-dump {_M_range_initialize<const char\* const\*>} "gimple" } } +// And that the backing array is static. +// { dg-final { scan-tree-dump {static const char.*72} "gimple" } } #include <string> #include <vector> diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C new file mode 100644 index 0000000..16e2e53 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C @@ -0,0 +1,13 @@ +// PR c++/110070 +// { dg-additional-options -fdump-tree-gimple } +// { dg-do compile { target c++11 } } + +// { dg-final { scan-tree-dump {static const int [^\n]*\[4\] = } "gimple" } } + +#include <initializer_list> +extern void ext(int); +void foo() +{ + for (int i: {1,2,4,6}) + ext(i); +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 9d44c04..6dd7b68 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1803,7 +1803,8 @@ struct GTY(()) tree_decl_common { In VAR_DECL, PARM_DECL and RESULT_DECL, this is DECL_HAS_VALUE_EXPR_P. */ unsigned decl_flag_2 : 1; - /* In FIELD_DECL, this is DECL_PADDING_P. */ + /* In FIELD_DECL, this is DECL_PADDING_P. + In VAR_DECL, this is DECL_MERGEABLE. */ unsigned decl_flag_3 : 1; /* Logically, these two would go in a theoretical base shared by var and parm decl. */ @@ -3233,6 +3233,12 @@ extern void decl_fini_priority_insert (tree, priority_type); #define DECL_NONALIASED(NODE) \ (VAR_DECL_CHECK (NODE)->base.nothrow_flag) +/* In a VAR_DECL, nonzero if this variable is not required to have a distinct + address from other variables with the same constant value. In other words, + consider -fmerge-all-constants to be on for this VAR_DECL. */ +#define DECL_MERGEABLE(NODE) \ + (VAR_DECL_CHECK (NODE)->decl_common.decl_flag_3) + /* This field is used to reference anything in decl.result and is meant only for use by the garbage collector. */ #define DECL_RESULT_FLD(NODE) \ diff --git a/gcc/varasm.cc b/gcc/varasm.cc index aee1aff..dd84754 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -7032,7 +7032,7 @@ categorize_decl_for_section (const_tree decl, int reloc) } else if (reloc & targetm.asm_out.reloc_rw_mask ()) ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO; - else if (reloc || flag_merge_constants < 2 + else if (reloc || (flag_merge_constants < 2 && !DECL_MERGEABLE (decl)) || ((flag_sanitize & SANITIZE_ADDRESS) /* PR 81697: for architectures that use section anchors we need to ignore DECL_RTL_SET_P (decl) for string constants |