If one writes p - ((intptr_t)p % align) to align a pointer we neither produce optimal code for the aligning nor can we track the alignment for the resulting pointer from within CCP. The following makes sure we transform the above to p & ~align instead.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2012-07-13 Richard Guenther <rguent...@suse.de> PR tree-optimization/53907 * tree-ssa-forwprop.c (associate_pointerplus): New function. (ssa_forward_propagate_and_combine): Call it. * gcc.target/i386/pr53907.c: New testcase. Index: gcc/tree-ssa-forwprop.c =================================================================== *** gcc/tree-ssa-forwprop.c (revision 189458) --- gcc/tree-ssa-forwprop.c (working copy) *************** *** 2474,2479 **** --- 2465,2523 ---- return false; } + /* 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, rhs, algn; + + /* Pattern match + tem = (sizetype) ptr; + tem = tem & algn; + tem = -tem; + ... = ptr p+ tem; + and produce the simpler and easier to analyze with respect to alignment + ... = ptr & ~algn; */ + ptr = gimple_assign_rhs1 (stmt); + rhs = gimple_assign_rhs2 (stmt); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + def_stmt = SSA_NAME_DEF_STMT (rhs); + if (!is_gimple_assign (def_stmt) + || gimple_assign_rhs_code (def_stmt) != NEGATE_EXPR) + return false; + rhs = gimple_assign_rhs1 (def_stmt); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + def_stmt = SSA_NAME_DEF_STMT (rhs); + if (!is_gimple_assign (def_stmt) + || gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR) + return false; + rhs = gimple_assign_rhs1 (def_stmt); + algn = gimple_assign_rhs2 (def_stmt); + if (TREE_CODE (rhs) != SSA_NAME + || TREE_CODE (algn) != INTEGER_CST) + 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; + if (gimple_assign_rhs1 (def_stmt) != ptr) + return false; + + algn = double_int_to_tree (TREE_TYPE (ptr), + double_int_not (tree_to_double_int (algn))); + gimple_assign_set_rhs_with_ops (gsi, BIT_AND_EXPR, ptr, algn); + fold_stmt_inplace (gsi); + update_stmt (stmt); + + return true; + } + /* Combine two conversions in a row for the second conversion at *GSI. Returns 1 if there were any changes made, 2 if cfg-cleanup needs to run. Else it returns 0. */ *************** ssa_forward_propagate_and_combine (void) *** 2815,2820 **** --- 2850,2857 ---- else if (code == PLUS_EXPR || code == MINUS_EXPR) changed = associate_plusminus (&gsi); + else if (code == POINTER_PLUS_EXPR) + changed = associate_pointerplus (&gsi); else if (CONVERT_EXPR_CODE_P (code) || code == FLOAT_EXPR || code == FIX_TRUNC_EXPR) Index: gcc/testsuite/gcc.target/i386/pr53907.c =================================================================== *** gcc/testsuite/gcc.target/i386/pr53907.c (revision 0) --- gcc/testsuite/gcc.target/i386/pr53907.c (working copy) *************** *** 0 **** --- 1,14 ---- + /* { dg-do compile } */ + /* { dg-options "-O -msse2" } */ + + #include <emmintrin.h> + + __m128i x(char *s) + { + __m128i sz,z,mvec; + s-=((unsigned long) s)%16; + sz=_mm_load_si128((__m128i *)s); + return sz; + } + + /* { dg-final { scan-assembler "movdqa" } } */