aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cgraph.cc2
-rw-r--r--gcc/cp/call.cc15
-rw-r--r--gcc/cp/tree.cc9
-rw-r--r--gcc/gimplify.cc3
-rw-r--r--gcc/testsuite/g++.dg/opt/icf1.C16
-rw-r--r--gcc/testsuite/g++.dg/opt/icf2.C17
-rw-r--r--gcc/testsuite/g++.dg/opt/icf3.C17
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/array-temp1.C6
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C1
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/initlist-opt2.C2
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/initlist-opt4.C13
-rw-r--r--gcc/tree-core.h3
-rw-r--r--gcc/tree.h6
-rw-r--r--gcc/varasm.cc2
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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 0b72663..8a4beba 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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