This fixes the rest, adding p + (q - p) pattern matching and (p + o1) + o2 associating (similar to the fold-const code).
And it adds testcases for the whole series. Bootstrapped and tested on x86_64-unknown-linux-gnu and applied. Richard. 2014-01-29 Richard Biener <rguent...@suse.de> PR tree-optimization/58742 * tree-ssa-forwprop.c (associate_pointerplus): Rename to associate_pointerplus_align. (associate_pointerplus_diff): New function. (associate_pointerplus): Likewise. Call associate_pointerplus_align and associate_pointerplus_diff. * gcc.dg/pr58742-1.c: New testcase. * gcc.dg/pr58742-2.c: Likewise. * gcc.dg/pr58742-3.c: Likewise. Index: gcc/tree-ssa-forwprop.c =================================================================== *** gcc/tree-ssa-forwprop.c (revision 207234) --- gcc/tree-ssa-forwprop.c (working copy) *************** out: *** 2802,2808 **** true if anything changed, false otherwise. */ static bool ! associate_pointerplus (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); gimple def_stmt; --- 2802,2808 ---- true if anything changed, false otherwise. */ static bool ! associate_pointerplus_align (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); gimple def_stmt; *************** associate_pointerplus (gimple_stmt_itera *** 2848,2853 **** --- 2848,2950 ---- update_stmt (stmt); return true; + } + + /* Associate operands of a POINTER_PLUS_EXPR assignmen at *GSI. Returns + true if anything changed, false otherwise. */ + + static bool + associate_pointerplus_diff (gimple_stmt_iterator *gsi) + { + gimple stmt = gsi_stmt (*gsi); + gimple def_stmt; + tree ptr1, rhs; + + /* Pattern match + tem1 = (long) ptr1; + tem2 = (long) ptr2; + tem3 = tem2 - tem1; + tem4 = (unsigned long) tem3; + tem5 = ptr1 + tem4; + and produce + tem5 = ptr2; */ + ptr1 = gimple_assign_rhs1 (stmt); + rhs = gimple_assign_rhs2 (stmt); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + gimple minus = SSA_NAME_DEF_STMT (rhs); + /* Conditionally look through a sign-changing conversion. */ + if (is_gimple_assign (minus) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (minus)) + && (TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (minus))) + == TYPE_PRECISION (TREE_TYPE (rhs))) + && TREE_CODE (gimple_assign_rhs1 (minus)) == SSA_NAME) + minus = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (minus)); + if (!is_gimple_assign (minus)) + return false; + if (gimple_assign_rhs_code (minus) != MINUS_EXPR) + return false; + rhs = gimple_assign_rhs2 (minus); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + def_stmt = SSA_NAME_DEF_STMT (rhs); + if (!is_gimple_assign (def_stmt) + || ! CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) + || gimple_assign_rhs1 (def_stmt) != ptr1) + return false; + rhs = gimple_assign_rhs1 (minus); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + def_stmt = SSA_NAME_DEF_STMT (rhs); + if (!is_gimple_assign (def_stmt) + || ! CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))) + return false; + rhs = gimple_assign_rhs1 (def_stmt); + if (! useless_type_conversion_p (TREE_TYPE (ptr1), TREE_TYPE (rhs))) + return false; + + gimple_assign_set_rhs_with_ops (gsi, TREE_CODE (rhs), rhs, NULL_TREE); + update_stmt (stmt); + + return true; + } + + /* Associate operands of a POINTER_PLUS_EXPR assignmen at *GSI. Returns + true if anything changed, false otherwise. */ + + static bool + associate_pointerplus (gimple_stmt_iterator *gsi) + { + gimple stmt = gsi_stmt (*gsi); + gimple def_stmt; + tree ptr, off1, off2; + + if (associate_pointerplus_align (gsi) + || associate_pointerplus_diff (gsi)) + return true; + + /* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */ + ptr = gimple_assign_rhs1 (stmt); + off1 = gimple_assign_rhs2 (stmt); + if (TREE_CODE (ptr) != SSA_NAME) + return false; + def_stmt = SSA_NAME_DEF_STMT (ptr); + if (!is_gimple_assign (def_stmt) + || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR) + return false; + ptr = gimple_assign_rhs1 (def_stmt); + off2 = gimple_assign_rhs2 (def_stmt); + if (!types_compatible_p (TREE_TYPE (off1), TREE_TYPE (off2))) + return false; + + tree off = make_ssa_name (TREE_TYPE (off1), NULL); + gimple ostmt = gimple_build_assign_with_ops (PLUS_EXPR, off, off1, off2); + gsi_insert_before (gsi, ostmt, GSI_SAME_STMT); + + gimple_assign_set_rhs_with_ops (gsi, POINTER_PLUS_EXPR, ptr, off); + update_stmt (stmt); + + return true; } /* Combine two conversions in a row for the second conversion at *GSI. Index: gcc/testsuite/gcc.dg/pr58742-1.c =================================================================== *** gcc/testsuite/gcc.dg/pr58742-1.c (revision 0) --- gcc/testsuite/gcc.dg/pr58742-1.c (working copy) *************** *** 0 **** --- 1,13 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-cddce1" } */ + + int * + fx (int *b, int *e) + { + __SIZE_TYPE__ p = e - b; + /* The first forwprop pass should optimize this to return e; */ + return b + p; + } + + /* { dg-final { scan-tree-dump "return e" "cddce1" } } */ + /* { dg-final { cleanup-tree-dump "cddce1" } } */ Index: gcc/testsuite/gcc.dg/pr58742-2.c =================================================================== *** gcc/testsuite/gcc.dg/pr58742-2.c (revision 0) --- gcc/testsuite/gcc.dg/pr58742-2.c (working copy) *************** *** 0 **** --- 1,13 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-cddce1" } */ + + __SIZE_TYPE__ + fx (char *a, __SIZE_TYPE__ sz) + { + char *b = a + sz; + /* The first forwprop pass should optimize this to return sz; */ + return b - a; + } + + /* { dg-final { scan-tree-dump "return sz" "cddce1" } } */ + /* { dg-final { cleanup-tree-dump "cddce1" } } */ Index: gcc/testsuite/gcc.dg/pr58742-3.c =================================================================== *** gcc/testsuite/gcc.dg/pr58742-3.c (revision 0) --- gcc/testsuite/gcc.dg/pr58742-3.c (working copy) *************** *** 0 **** --- 1,14 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-cddce1" } */ + + int * + fx (int *a, int sz) + { + int *b = a + sz; + b = b - sz; + /* forwprop together with FRE should optimize this to return a; */ + return b; + } + + /* { dg-final { scan-tree-dump "return a" "cddce1" } } */ + /* { dg-final { cleanup-tree-dump "cddce1" } } */