This moves the value_replacement support for jump_function_from_stmt
to match pattern.
This allows us to optimize things earlier in phiopt1 rather than waiting
to phiopt2. Which means phiopt1 needs to be disable for vrp03.c testcase.

Bootstrapped and tested on x86_64-linux-gnu.

gcc/ChangeLog:

        * match.pd (PTR == 0 ? 0 : &PTR->field): New pattern.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/vrp03.c: Disable phiopt1.
        * c-c++-common/analyzer/inlining-3-multiline.c: Likewise.
        * c-c++-common/analyzer/inlining-3.c: Likewise.
        * gcc.dg/tree-ssa/phi-opt-value-3.c: New testcase.
---
 gcc/match.pd                                  | 21 ++++++++++++++++++
 .../analyzer/inlining-3-multiline.c           |  5 ++++-
 .../c-c++-common/analyzer/inlining-3.c        |  3 +++
 .../gcc.dg/tree-ssa/phi-opt-value-3.c         | 22 +++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp03.c         |  2 +-
 5 files changed, 51 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-3.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 22899c51a2f..9bc945ccada 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4159,6 +4159,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (cond (eq @0 integer_zerop) @1 (op@2 @1 @0))
    @2))
 
+/* PTR == 0 ? 0 : &PTR->field -> PTR if field offset was 0. */
+(simplify
+ (cond (eq @0 integer_zerop) integer_zerop ADDR_EXPR@1)
+ (with {
+   poly_int64 offset;
+   tree res = NULL_TREE;
+   tree tem = @1;
+   if (TREE_CODE (tem) == SSA_NAME)
+     if (gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (tem)))
+       if (gimple_assign_rhs_code (def) == ADDR_EXPR)
+         tem = gimple_assign_rhs1 (def);
+
+   if (TREE_CODE (tem) == ADDR_EXPR)
+     res = get_addr_base_and_unit_offset (TREE_OPERAND (tem, 0), &offset);
+  }
+  (if (res
+       && TREE_CODE (res) == MEM_REF
+       && known_eq (mem_ref_offset (res) + offset, 0)
+       && operand_equal_p (TREE_OPERAND (res, 0), @0))
+   (convert @0))))
+
 /* Simplifications of shift and rotates.  */
 
 (for rotate (lrotate rrotate)
diff --git a/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c 
b/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c
index fbd20e949b6..9741b91abee 100644
--- a/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c
+++ b/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c
@@ -3,6 +3,9 @@
 
 /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */
 /* { dg-additional-options "-fdiagnostics-path-format=inline-events 
-fdiagnostics-show-caret" } */
+/* Disable phi-opt1 because get_input_file_name gets optimized to just
+   `return inpf;`. */
+/* { dg-additional-options "-fdisable-tree-phiopt1" } */
 
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 typedef __SIZE_TYPE__ size_t;
@@ -96,4 +99,4 @@ test (const input_file *inpf)
     |                           (4) ...to here
     |                           (5) argument 1 ('<unknown>') NULL where 
non-null expected
     |
-   { dg-end-multiline-output "" { target c++ } } */
\ No newline at end of file
+   { dg-end-multiline-output "" { target c++ } } */
diff --git a/gcc/testsuite/c-c++-common/analyzer/inlining-3.c 
b/gcc/testsuite/c-c++-common/analyzer/inlining-3.c
index 0345585bed2..2b2b4858d45 100644
--- a/gcc/testsuite/c-c++-common/analyzer/inlining-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/inlining-3.c
@@ -2,6 +2,9 @@
    after early inlining.  */
 
 /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */
+/* Disable phi-opt1 because get_input_file_name gets optimized to just
+   `return inpf;`. */
+/* { dg-additional-options "-fdisable-tree-phiopt1" } */
 
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 typedef __SIZE_TYPE__ size_t;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-3.c
new file mode 100644
index 00000000000..ad55bd288b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile }  */
+/* { dg-options "-O1 -fdump-tree-optimized" }  */
+struct a
+{
+        int b[1];
+};
+
+int call1(int *a);
+
+int f(struct a *b)
+{
+  int *c = b->b;
+  int t = call1(c);
+  int *d;
+  if (b) d = b->b; else d = 0;
+  int t1 = call1(d);
+  return t+t1;
+}
+
+/* There should be no if statement and 2 calls to call1. */
+/* { dg-final { scan-tree-dump-not "if " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "call1 " 2 "optimized"  } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp03.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp03.c
index 4cbaca41332..1adbf33cad3 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp03.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp03.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-thread-jumps" } 
*/
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fno-thread-jumps 
-fdisable-tree-phiopt1" } */
 
 struct A
 {
-- 
2.39.3

Reply via email to