This adds the ability to the simple dse to remove the lhs of a
call. It can also remove a call if it was pure/const in some cases.
On trampv3, I found this happened a few times during forwprop2, 3
and 4. The one in 4 was a suprise and even more it caused a removal
of a call which gcc was not able to remove before. This is due to
the nature of DSE/DCE needs to be done iteratively together but
we currently don't do that. So it just happens the late forwprop4's
simple dse is able to remove this call.
I will fix the xfail testcases in a followup, basically there exceptions
can get a mismatch in the CLOBBER which I didn't expect before and I was
being super cautious when it comes having them match but in reality
the difference in CLOBBERs don't matter.
Bootstrapped and tested on x86_64-linux-gnu
PR tree-optimization/122633
gcc/ChangeLog:
* tree-ssa-forwprop.cc (do_simple_agr_dse): Remove
lhs of dead store for a call (or the whole call stmt).
gcc/testsuite/ChangeLog:
* g++.dg/tree-ssa/simple-dse-1.C: New test.
* g++.dg/tree-ssa/simple-dse-2.C: New test.
* g++.dg/tree-ssa/simple-dse-3.C: New test.
* g++.dg/tree-ssa/simple-dse-4.C: New test.
Signed-off-by: Andrew Pinski <[email protected]>
---
gcc/testsuite/g++.dg/tree-ssa/simple-dse-1.C | 28 +++++++++++
gcc/testsuite/g++.dg/tree-ssa/simple-dse-2.C | 28 +++++++++++
gcc/testsuite/g++.dg/tree-ssa/simple-dse-3.C | 28 +++++++++++
gcc/testsuite/g++.dg/tree-ssa/simple-dse-4.C | 30 +++++++++++
gcc/tree-ssa-forwprop.cc | 53 ++++++++++++++++++--
5 files changed, 164 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/tree-ssa/simple-dse-1.C
create mode 100644 gcc/testsuite/g++.dg/tree-ssa/simple-dse-2.C
create mode 100644 gcc/testsuite/g++.dg/tree-ssa/simple-dse-3.C
create mode 100644 gcc/testsuite/g++.dg/tree-ssa/simple-dse-4.C
diff --git a/gcc/testsuite/g++.dg/tree-ssa/simple-dse-1.C
b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-1.C
new file mode 100644
index 00000000000..20db9d49414
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-1.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-exceptions -fdump-tree-forwprop1-details" }
+// PR tree-optimization/122633
+
+struct s1
+{
+ int f1[4];
+ ~s1(){}
+};
+
+struct s1 func1(int a);
+void func2(int a)
+{
+ struct s1 v1 = func1(a);
+}
+
+__attribute__((pure))
+struct s1 pure1(int a);
+void func3(int a)
+{
+ struct s1 p1 = pure1(a);
+}
+
+// { dg-final { scan-tree-dump "Removing dead call store stmt p1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-not "Removing dead call store stmt v1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-not "Removing lhs of call stmt " "forwprop1" } }
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 1
"forwprop1" } }
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/simple-dse-2.C
b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-2.C
new file mode 100644
index 00000000000..a4a5a9ff51e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-2.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-exceptions -fdump-tree-forwprop1-details" }
+// PR tree-optimization/122633
+struct s1
+{
+ int f1[4];
+};
+
+struct s1 func1(int a);
+void func2(int a)
+{
+ struct s1 v1 = func1(a);
+}
+
+__attribute__((pure))
+struct s1 pure1(int a);
+void func3(int a)
+{
+ struct s1 p1 = pure1(a);
+}
+
+// { dg-final { scan-tree-dump-not "Removing lhs of call stmt p1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-not "Removing dead call store stmt v1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump "Removing lhs of call stmt v1 =" "forwprop1" } }
+// { dg-final { scan-tree-dump "Removing dead call store stmt p1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 1
"forwprop1" } }
+// { dg-final { scan-tree-dump-times "Removing lhs of call stmt" 1 "forwprop1"
} }
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/simple-dse-3.C
b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-3.C
new file mode 100644
index 00000000000..dc31eff3be3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-3.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-O2 -fexceptions -fdump-tree-forwprop1-details" }
+// PR tree-optimization/122633
+struct s1
+{
+ int f1[4];
+ ~s1(){}
+};
+
+struct s1 func1(int a);
+void func2(int a)
+{
+ struct s1 v1 = func1(a);
+}
+
+__attribute__((pure))
+struct s1 pure1(int a);
+void func3(int a)
+{
+ struct s1 p1 = pure1(a);
+}
+
+// { dg-final { scan-tree-dump "Removing dead call store stmt p1 ="
"forwprop1" { xfail *-*-* } } }
+// { dg-final { scan-tree-dump-not "Removing dead call store stmt v1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-not "Removing lhs of call stmt " "forwprop1" } }
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 1
"forwprop1" { target { ! c++26 } xfail *-*-* } } }
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 2
"forwprop1" { target c++26 xfail *-*-* } } }
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/simple-dse-4.C
b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-4.C
new file mode 100644
index 00000000000..1b9ad076134
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/simple-dse-4.C
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-O2 -fexceptions -fdump-tree-forwprop1-details" }
+// PR tree-optimization/122633
+struct s1
+{
+ int f1[4];
+};
+
+struct s1 func1(int a);
+void func2(int a)
+{
+ struct s1 v1 = func1(a);
+}
+
+__attribute__((pure))
+struct s1 pure1(int a);
+void func3(int a)
+{
+ struct s1 p1 = pure1(a);
+}
+
+// { dg-final { scan-tree-dump-not "Removing lhs of call stmt p1 ="
"forwprop1" } }
+// { dg-final { scan-tree-dump-not "Removing dead call store stmt v1 = func1"
"forwprop1" } }
+// { dg-final { scan-tree-dump "Removing lhs of call stmt v1 =" "forwprop1" } }
+// { dg-final { scan-tree-dump "Removing dead call store stmt p1 ="
"forwprop1" } }
+// v1 has an DEFERRED_INIT associated with it (due to exceptions)
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 1
"forwprop1" { target { ! c++26 } } } }
+// { dg-final { scan-tree-dump-times "Removing dead call store stmt" 2
"forwprop1" { target c++26 } } }
+// { dg-final { scan-tree-dump-times "Removing lhs of call stmt" 1 "forwprop1"
} }
+
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 052d1740491..a744e224d99 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -1842,10 +1842,57 @@ do_simple_agr_dse (gassign *stmt, bool full_walk)
return;
}
vuse = gimple_vuse (ostmt);
-
+ /* This is a call with an assignment to the clobber decl,
+ remove the lhs or the whole stmt if it was pure/const. */
+ if (is_a <gcall*>(ostmt)
+ && lhs == gimple_call_lhs (ostmt))
+ {
+ /* Don't remove stores/statements that are needed for non-call
+ eh to work. */
+ if (stmt_unremovable_because_of_non_call_eh_p (cfun, ostmt))
+ return;
+ /* If we delete a stmt that could throw, mark the block
+ in to_purge to cleanup afterwards. */
+ if (stmt_could_throw_p (cfun, ostmt))
+ bitmap_set_bit (to_purge, obb->index);
+ int flags = gimple_call_flags (ostmt);
+ if ((flags & (ECF_PURE|ECF_CONST|ECF_NOVOPS))
+ && !(flags & (ECF_LOOPING_CONST_OR_PURE)))
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (ostmt);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Removing dead call store stmt ");
+ print_gimple_stmt (dump_file, ostmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ unlink_stmt_vdef (ostmt);
+ release_defs (ostmt);
+ gsi_remove (&gsi, true);
+ statistics_counter_event (cfun, "delete call dead store", 1);
+ /* Only remove the first store previous statement. */
+ return;
+ }
+ /* Make sure we do not remove a return slot we cannot reconstruct
+ later. */
+ if (gimple_call_return_slot_opt_p (as_a <gcall *>(ostmt))
+ && (TREE_ADDRESSABLE (TREE_TYPE (gimple_call_fntype (ostmt)))
+ || !poly_int_tree_p
+ (TYPE_SIZE (TREE_TYPE (gimple_call_fntype (ostmt))))))
+ return;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Removing lhs of call stmt ");
+ print_gimple_stmt (dump_file, ostmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ gimple_call_set_lhs (ostmt, NULL_TREE);
+ update_stmt (ostmt);
+ statistics_counter_event (cfun, "removed lhs call", 1);
+ return;
+ }
/* This an assignment store to the clobbered decl,
- then maybe remove it. A call is not handled here as
- the rhs will not make a difference for SRA. */
+ then maybe remove it. */
if (is_a <gassign*>(ostmt)
&& gimple_store_p (ostmt)
&& !gimple_clobber_p (ostmt)
--
2.43.0