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" } } */

Reply via email to