This fixes PR58697 by instead of trying to preserve reference structure when generating initial loads for the predictive commoned loop, just builds an approprate MEM_REF. That now can handle the cases that previously could be discovered as non-trapping (all constant offsets).
I don't see a better way avoiding the out-of-bounds array access it currently generates (with preserving the transformation and not regressing other testcases). Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2013-11-06 Richard Biener <rguent...@suse.de> PR tree-optimization/58653 * tree-predcom.c (ref_at_iteration): Rewrite to generate a MEM_REF. (prepare_initializers_chain): Adjust. * gcc.dg/tree-ssa/predcom-6.c: New testcase. * gcc.dg/tree-ssa/predcom-7.c: Likewise. Index: gcc/tree-predcom.c =================================================================== *** gcc/tree-predcom.c (revision 204396) --- gcc/tree-predcom.c (working copy) *************** replace_ref_with (gimple stmt, tree new_ *** 1323,1412 **** gsi_insert_after (&bsi, new_stmt, GSI_NEW_STMT); } ! /* Returns the reference to the address of REF in the ITER-th iteration of ! LOOP, or NULL if we fail to determine it (ITER may be negative). We ! try to preserve the original shape of the reference (not rewrite it ! as an indirect ref to the address), to make tree_could_trap_p in ! prepare_initializers_chain return false more often. */ ! static tree ! ref_at_iteration (struct loop *loop, tree ref, int iter) { ! tree idx, *idx_p, type, val, op0 = NULL_TREE, ret; ! affine_iv iv; ! bool ok; ! ! if (handled_component_p (ref)) ! { ! op0 = ref_at_iteration (loop, TREE_OPERAND (ref, 0), iter); ! if (!op0) ! return NULL_TREE; ! } ! else if (!INDIRECT_REF_P (ref) ! && TREE_CODE (ref) != MEM_REF) ! return unshare_expr (ref); ! ! if (TREE_CODE (ref) == MEM_REF) ! { ! ret = unshare_expr (ref); ! idx = TREE_OPERAND (ref, 0); ! idx_p = &TREE_OPERAND (ret, 0); ! } ! else if (TREE_CODE (ref) == COMPONENT_REF) ! { ! /* Check that the offset is loop invariant. */ ! if (TREE_OPERAND (ref, 2) ! && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2))) ! return NULL_TREE; ! ! return build3 (COMPONENT_REF, TREE_TYPE (ref), op0, ! unshare_expr (TREE_OPERAND (ref, 1)), ! unshare_expr (TREE_OPERAND (ref, 2))); ! } ! else if (TREE_CODE (ref) == ARRAY_REF) ! { ! /* Check that the lower bound and the step are loop invariant. */ ! if (TREE_OPERAND (ref, 2) ! && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2))) ! return NULL_TREE; ! if (TREE_OPERAND (ref, 3) ! && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 3))) ! return NULL_TREE; ! ! ret = build4 (ARRAY_REF, TREE_TYPE (ref), op0, NULL_TREE, ! unshare_expr (TREE_OPERAND (ref, 2)), ! unshare_expr (TREE_OPERAND (ref, 3))); ! idx = TREE_OPERAND (ref, 1); ! idx_p = &TREE_OPERAND (ret, 1); ! } ! else ! return NULL_TREE; ! ! ok = simple_iv (loop, loop, idx, &iv, true); ! if (!ok) ! return NULL_TREE; ! iv.base = expand_simple_operations (iv.base); ! if (integer_zerop (iv.step)) ! *idx_p = unshare_expr (iv.base); else ! { ! type = TREE_TYPE (iv.base); ! if (POINTER_TYPE_P (type)) ! { ! val = fold_build2 (MULT_EXPR, sizetype, iv.step, ! size_int (iter)); ! val = fold_build_pointer_plus (iv.base, val); ! } ! else ! { ! val = fold_build2 (MULT_EXPR, type, iv.step, ! build_int_cst_type (type, iter)); ! val = fold_build2 (PLUS_EXPR, type, iv.base, val); ! } ! *idx_p = unshare_expr (val); ! } ! ! return ret; } /* Get the initialization expression for the INDEX-th temporary variable --- 1323,1351 ---- gsi_insert_after (&bsi, new_stmt, GSI_NEW_STMT); } ! /* Returns a memory reference to DR in the ITER-th iteration of ! the loop it was analyzed in. Append init stmts to STMTS. */ ! static tree ! ref_at_iteration (data_reference_p dr, int iter, gimple_seq *stmts) { ! tree off = DR_OFFSET (dr); ! tree coff = DR_INIT (dr); ! if (iter == 0) ! ; ! else if (TREE_CODE (DR_STEP (dr)) == INTEGER_CST) ! coff = size_binop (PLUS_EXPR, coff, ! size_binop (MULT_EXPR, DR_STEP (dr), ssize_int (iter))); else ! off = size_binop (PLUS_EXPR, off, ! size_binop (MULT_EXPR, DR_STEP (dr), ssize_int (iter))); ! tree addr = fold_build_pointer_plus (DR_BASE_ADDRESS (dr), off); ! addr = force_gimple_operand_1 (addr, stmts, is_gimple_mem_ref_addr, ! NULL_TREE); ! return fold_build2 (MEM_REF, TREE_TYPE (DR_REF (dr)), ! addr, ! fold_convert (reference_alias_ptr_type (DR_REF (dr)), ! coff)); } /* Get the initialization expression for the INDEX-th temporary variable *************** prepare_initializers_chain (struct loop *** 2365,2378 **** if (chain->inits[i] != NULL_TREE) continue; ! init = ref_at_iteration (loop, DR_REF (dr), (int) i - n); ! if (!init) ! return false; ! if (!chain->all_always_accessed && tree_could_trap_p (init)) return false; - init = force_gimple_operand (init, &stmts, false, NULL_TREE); if (stmts) gsi_insert_seq_on_edge_immediate (entry, stmts); --- 2304,2313 ---- if (chain->inits[i] != NULL_TREE) continue; ! init = ref_at_iteration (dr, (int) i - n, &stmts); if (!chain->all_always_accessed && tree_could_trap_p (init)) return false; if (stmts) gsi_insert_seq_on_edge_immediate (entry, stmts); Index: gcc/testsuite/gcc.dg/tree-ssa/predcom-6.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/predcom-6.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/predcom-6.c (working copy) *************** *** 0 **** --- 1,17 ---- + /* { dg-do run } */ + /* { dg-options "-O3 -fdump-tree-pcom-details" } */ + + int a, c, e[5][2]; + unsigned int d; + + int + main () + { + for (d = 0; d < 2; d++) + if (a ? 0 : e[c + 3][d] & e[c + 4][d]) + break; + return 0; + } + + /* { dg-final { scan-tree-dump "Executing predictive commoning" "pcom" } } */ + /* { dg-final { cleanup-tree-dump "pcom" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/predcom-7.c (working copy) @@ -0,0 +1,18 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fdump-tree-pcom-details" } */ + +int b, f, d[5][2]; +unsigned int c; + +int +main () +{ + for (c = 0; c < 2; c++) + if (d[b + 3][c] & d[b + 4][c]) + if (f) + break; + return 0; +} + +/* { dg-final { scan-tree-dump "Executing predictive commoning" "pcom" } } */ +/* { dg-final { cleanup-tree-dump "pcom" } } */