This implements the missing outlining of loop tree parts in
move_sese_region_to_fn (used by OMP lowering and thus autopar).

Testing coverage is somewhat weak because OMP lowering doesn't
update the loop tree when building loops.  Something to be fixed
so the loop fixup can be avoided.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2013-04-26  Richard Biener  <rguent...@suse.de>

        * omp-low.c (finalize_task_copyfn): Do not drop PROP_loops.
        (expand_omp_taskreg): Likewise.  Mark loops for fixup.
        * tree-cfg.c (move_block_to_fn): Remap loop fathers.
        (fixup_loop_arrays_after_move): New function.
        (move_sese_region_to_fn): Properly outline the loop tree parts
        of the SESE region.

Index: trunk/gcc/omp-low.c
===================================================================
*** trunk.orig/gcc/omp-low.c    2013-04-26 11:27:31.000000000 +0200
--- trunk/gcc/omp-low.c 2013-04-26 12:01:56.643354202 +0200
*************** finalize_task_copyfn (gimple task_stmt)
*** 1258,1267 ****
      return;
  
    child_cfun = DECL_STRUCT_FUNCTION (child_fn);
! 
!   /* Inform the callgraph about the new function.  */
!   DECL_STRUCT_FUNCTION (child_fn)->curr_properties
!     = cfun->curr_properties & ~PROP_loops;
  
    push_cfun (child_cfun);
    bind = gimplify_body (child_fn, false);
--- 1258,1264 ----
      return;
  
    child_cfun = DECL_STRUCT_FUNCTION (child_fn);
!   DECL_STRUCT_FUNCTION (child_fn)->curr_properties = cfun->curr_properties;
  
    push_cfun (child_cfun);
    bind = gimplify_body (child_fn, false);
*************** finalize_task_copyfn (gimple task_stmt)
*** 1276,1281 ****
--- 1273,1279 ----
    gimple_set_body (child_fn, seq);
    pop_cfun ();
  
+   /* Inform the callgraph about the new function.  */
    cgraph_add_new_function (child_fn, false);
  }
  
*************** expand_omp_taskreg (struct omp_region *r
*** 3573,3578 ****
--- 3571,3581 ----
        new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
        if (exit_bb)
        single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+       /* ???  As the OMP expansion process does not update the loop
+          tree of the original function before outlining the region to
+        the new child function we need to discover loops in the child.
+        Arrange for that.  */
+       child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
  
        /* Remove non-local VAR_DECLs from child_cfun->local_decls list.  */
        num = vec_safe_length (child_cfun->local_decls);
*************** expand_omp_taskreg (struct omp_region *r
*** 3589,3596 ****
        vec_safe_truncate (child_cfun->local_decls, dstidx);
  
        /* Inform the callgraph about the new function.  */
!       DECL_STRUCT_FUNCTION (child_fn)->curr_properties
!       = cfun->curr_properties & ~PROP_loops;
        cgraph_add_new_function (child_fn, true);
  
        /* Fix the callgraph edges for child_cfun.  Those for cfun will be
--- 3592,3598 ----
        vec_safe_truncate (child_cfun->local_decls, dstidx);
  
        /* Inform the callgraph about the new function.  */
!       DECL_STRUCT_FUNCTION (child_fn)->curr_properties = 
cfun->curr_properties;
        cgraph_add_new_function (child_fn, true);
  
        /* Fix the callgraph edges for child_cfun.  Those for cfun will be
Index: trunk/gcc/tree-cfg.c
===================================================================
*** trunk.orig/gcc/tree-cfg.c   2013-04-26 11:27:31.000000000 +0200
--- trunk/gcc/tree-cfg.c        2013-04-26 12:59:55.282564848 +0200
*************** move_block_to_fn (struct function *dest_
*** 6366,6373 ****
  
    /* Remove BB from dominance structures.  */
    delete_from_dominance_info (CDI_DOMINATORS, bb);
    if (current_loops)
!     remove_bb_from_loops (bb);
  
    /* Link BB to the new linked list.  */
    move_block_after (bb, after);
--- 6366,6379 ----
  
    /* Remove BB from dominance structures.  */
    delete_from_dominance_info (CDI_DOMINATORS, bb);
+ 
+   /* Move BB from its current loop to the copy in the new function.  */
    if (current_loops)
!     {
!       struct loop *new_loop = (struct loop *)bb->loop_father->aux;
!       if (new_loop)
!       bb->loop_father = new_loop;
!     }
  
    /* Link BB to the new linked list.  */
    move_block_after (bb, after);
*************** replace_block_vars_by_duplicates (tree b
*** 6599,6604 ****
--- 6605,6629 ----
      replace_block_vars_by_duplicates (block, vars_map, to_context);
  }
  
+ /* Fixup the loop arrays and numbers after moving LOOP and its subloops
+    from FN1 to FN2.  */
+ 
+ static void
+ fixup_loop_arrays_after_move (struct function *fn1, struct function *fn2,
+                             struct loop *loop)
+ {
+   /* Discard it from the old loop array.  */
+   (*fn1->x_current_loops->larray)[loop->num] = NULL;
+ 
+   /* Place it in the new loop array, assigning it a new number.  */
+   loop->num = vec_safe_length (fn2->x_current_loops->larray);
+   vec_safe_push (fn2->x_current_loops->larray, loop);
+ 
+   /* Recurse to children.  */
+   for (loop = loop->inner; loop; loop = loop->next)
+     fixup_loop_arrays_after_move (fn1, fn2, loop);
+ }
+ 
  /* Move a single-entry, single-exit region delimited by ENTRY_BB and
     EXIT_BB to function DEST_CFUN.  The whole region is replaced by a
     single basic block in the original CFG and the new basic block is
*************** move_sese_region_to_fn (struct function
*** 6718,6723 ****
--- 6743,6784 ----
        }
      }
  
+   /* Initialize an empty loop tree.  */
+   dest_cfun->x_current_loops = ggc_alloc_cleared_loops ();
+   init_loops_structure (dest_cfun, dest_cfun->x_current_loops, 1);
+   dest_cfun->x_current_loops->state = LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
+ 
+   /* Move the outlined loop tree part.  */
+   FOR_EACH_VEC_ELT (bbs, i, bb)
+     {
+       if (bb->loop_father->header == bb
+         && loop_outer (bb->loop_father) == loop)
+       {
+         struct loop *loop = bb->loop_father;
+         flow_loop_tree_node_remove (bb->loop_father);
+         flow_loop_tree_node_add (dest_cfun->x_current_loops->tree_root, loop);
+         fixup_loop_arrays_after_move (saved_cfun, cfun, loop);
+       }
+ 
+       /* Remove loop exits from the outlined region.  */
+       if (saved_cfun->x_current_loops->exits)
+       FOR_EACH_EDGE (e, ei, bb->succs)
+         {
+           void **slot = htab_find_slot_with_hash
+               (saved_cfun->x_current_loops->exits, e,
+                htab_hash_pointer (e), NO_INSERT);
+           if (slot)
+             htab_clear_slot (saved_cfun->x_current_loops->exits, slot);
+         }
+     }
+ 
+ 
+   /* Adjust the number of blocks in the tree root of the outlined part.  */
+   dest_cfun->x_current_loops->tree_root->num_nodes = bbs.length () + 2;
+ 
+   /* Setup a mapping to be used by move_block_to_fn.  */
+   loop->aux = current_loops->tree_root;
+ 
    pop_cfun ();
  
    /* Move blocks from BBS into DEST_CFUN.  */
*************** move_sese_region_to_fn (struct function
*** 6735,6752 ****
    d.eh_map = eh_map;
    d.remap_decls_p = true;
  
-   /* Cancel all loops inside the SESE region.
-      ???  We rely on loop fixup because loop structure is not 100%
-      up-to-date when called from OMP lowering and thus cancel_loop_tree
-      will not work.
-      ???  Properly move loops to the outlined function.  */
-   FOR_EACH_VEC_ELT (bbs, i, bb)
-     if (bb->loop_father->header == bb)
-       {
-       bb->loop_father->header = NULL;
-       bb->loop_father->latch = NULL;
-       loops_state_set (LOOPS_NEED_FIXUP);
-       }
    FOR_EACH_VEC_ELT (bbs, i, bb)
      {
        /* No need to update edge counts on the last block.  It has
--- 6796,6801 ----
*************** move_sese_region_to_fn (struct function
*** 6756,6761 ****
--- 6805,6817 ----
        after = bb;
      }
  
+   loop->aux = NULL;
+   /* Loop sizes are no longer correct, fix them up.  */
+   loop->num_nodes -= bbs.length ();
+   for (struct loop *outer = loop_outer (loop);
+        outer; outer = loop_outer (outer))
+     outer->num_nodes -= bbs.length ();
+ 
    /* Rewire BLOCK_SUBBLOCKS of orig_block.  */
    if (orig_block)
      {

Reply via email to