ggc.h (GGC_RESIZEVAR): New, reorder macros.
[gcc.git] / gcc / tree-parloops.c
index ca829f79f43557ac76bf05547c1e5efe3ef1c0c9..be0fd9cbac42c1cf0aa5a95aece33f508658f24c 100644 (file)
@@ -1,5 +1,5 @@
 /* Loop autoparallelization.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Sebastian Pop <pop@cri.ensmp.fr> and
    Zdenek Dvorak <dvorakz@suse.cz>.
 
@@ -106,25 +106,22 @@ parloop
 ....
 
 
-  # A new variable is created for each reduction:
-  "reduction_initial" is the initial value given by the user.
-  It is kept and will be used after the parallel computing is done.  #
+  # Storing the initial value given by the user.  #
 
-  reduction_initial.24_46 = 1;
-  
-  # Storing the neutral value of the
-  particular reduction's operation, e.g. 0 for PLUS_EXPR, 
-  1 for MULT_EXPR, etc. into the reduction field.
-  This is done in create_stores_for_reduction.  #
+  .paral_data_store.32.sum.27 = 1;
  
-  .paral_data_store.32.sum.27 = 0;
-  
   #pragma omp parallel num_threads(4) 
 
   #pragma omp for schedule(static)
-  # sum.27_29 = PHI <sum.27_11, 0> # The neutral element replaces
-                                  the user's inital value.  #
+
+  # The neutral element corresponding to the particular
+  reduction's operation, e.g. 0 for PLUS_EXPR,
+  1 for MULT_EXPR, etc. replaces the user's initial value.  #
+
+  # sum.27_29 = PHI <sum.27_11, 0>
+
   sum.27_11 = D.1827_8 + sum.27_29;
+
   OMP_CONTINUE
 
   # Adding this reduction phi is done at create_phi_for_local_result() #
@@ -143,12 +140,12 @@ parloop
   
  # collecting the result after the join of the threads is done at
   create_loads_for_reductions().
-  a new variable "reduction_final" is created.  It calculates the final
-  value from the initial value and the value computed by the threads #
+  The value computed by the threads is loaded from the
+  shared struct.  #
+
  
   .paral_data_load.33_52 = &.paral_data_store.32;
-  reduction_final.34_53 = .paral_data_load.33_52->sum.27;
-  sum_37 = reduction_initial.24_46 + reduction_final.34_53;
+  sum_37 =  .paral_data_load.33_52->sum.27;
   sum_43 = D.1795_41 + sum_37;
 
   exit bb:
@@ -174,8 +171,7 @@ struct reduction_info
   enum tree_code reduction_code;       /* code for the reduction operation.  */
   tree keep_res;               /* The PHI_RESULT of this phi is the resulting value 
                                   of the reduction variable when existing the loop. */
-  tree initial_value;          /* An ssa name representing a new variable holding
-                                  the initial value of the reduction var before entering the loop.   */
+  tree initial_value;          /* The initial value of the reduction var before entering the loop.  */
   tree field;                  /*  the name of the field in the parloop data structure intended for reduction.  */
   tree init;                   /* reduction initialization value.  */
   tree new_phi;                        /* (helper field) Newly created phi node whose result 
@@ -212,7 +208,7 @@ reduction_phi (htab_t reduction_list, tree phi)
     return NULL;
 
   tmpred.reduc_phi = phi;
-  red = htab_find (reduction_list, &tmpred);
+  red = (struct reduction_info *) htab_find (reduction_list, &tmpred);
 
   return red;
 }
@@ -321,6 +317,9 @@ loop_parallel_p (struct loop *loop, htab_t reduction_list, struct tree_niter_des
        }
     }
 
+  /* Get rid of the information created by the vectorizer functions.  */
+  destroy_loop_vec_info (simple_loop_info, true);
+
   for (phi = phi_nodes (exit->dest); phi; phi = PHI_CHAIN (phi))
     {
       struct reduction_info *red;
@@ -435,29 +434,56 @@ loop_parallel_p (struct loop *loop, htab_t reduction_list, struct tree_niter_des
   return ret;
 }
 
-/* Assigns the address of VAR in TYPE to an ssa name, and returns this name.
-   The assignment statement is placed before LOOP.  DECL_ADDRESS maps decls
-   to their addresses that can be reused.  */
+/* Return true when LOOP contains basic blocks marked with the
+   BB_IRREDUCIBLE_LOOP flag.  */
+
+static inline bool
+loop_has_blocks_with_irreducible_flag (struct loop *loop)
+{
+  unsigned i;
+  basic_block *bbs = get_loop_body_in_dom_order (loop);
+  bool res = true;
+
+  for (i = 0; i < loop->num_nodes; i++)
+    if (bbs[i]->flags & BB_IRREDUCIBLE_LOOP)
+      goto end;
+
+  res = false;
+ end:
+  free (bbs);
+  return res;
+}
+
+/* Assigns the address of OBJ in TYPE to an ssa name, and returns this name.
+   The assignment statement is placed on edge ENTRY.  DECL_ADDRESS maps decls
+   to their addresses that can be reused.  The address of OBJ is known to
+   be invariant in the whole function.  */
 
 static tree
-take_address_of (tree var, tree type, struct loop *loop, htab_t decl_address)
+take_address_of (tree obj, tree type, edge entry, htab_t decl_address)
 {
-  int uid = DECL_UID (var);
+  int uid;
   void **dslot;
   struct int_tree_map ielt, *nielt;
-  tree name, bvar, stmt;
-  edge entry = loop_preheader_edge (loop);
+  tree *var_p, name, bvar, stmt, addr;
+
+  /* Since the address of OBJ is invariant, the trees may be shared.
+     Avoid rewriting unrelated parts of the code.  */
+  obj = unshare_expr (obj);
+  for (var_p = &obj;
+       handled_component_p (*var_p);
+       var_p = &TREE_OPERAND (*var_p, 0))
+    continue;
+  uid = DECL_UID (*var_p);
 
   ielt.uid = uid;
   dslot = htab_find_slot_with_hash (decl_address, &ielt, uid, INSERT);
   if (!*dslot)
     {
-      bvar = create_tmp_var (type, get_name (var));
+      addr = build_addr (*var_p, current_function_decl);
+      bvar = create_tmp_var (TREE_TYPE (addr), get_name (*var_p));
       add_referenced_var (bvar);
-      stmt = build_gimple_modify_stmt (bvar,
-                                      fold_convert (type,
-                                                    build_addr (var,
-                                                                current_function_decl)));
+      stmt = build_gimple_modify_stmt (bvar, addr);
       name = make_ssa_name (bvar, stmt);
       GIMPLE_STMT_OPERAND (stmt, 0) = name;
       bsi_insert_on_edge_immediate (entry, stmt);
@@ -466,19 +492,26 @@ take_address_of (tree var, tree type, struct loop *loop, htab_t decl_address)
       nielt->uid = uid;
       nielt->to = name;
       *dslot = nielt;
-
-      return name;
     }
+  else
+    name = ((struct int_tree_map *) *dslot)->to;
 
-  name = ((struct int_tree_map *) *dslot)->to;
-  if (TREE_TYPE (name) == type)
-    return name;
+  if (var_p != &obj)
+    {
+      *var_p = build1 (INDIRECT_REF, TREE_TYPE (*var_p), name);
+      name = force_gimple_operand (build_addr (obj, current_function_decl),
+                                  &stmt, true, NULL_TREE);
+      if (stmt)
+       bsi_insert_on_edge_immediate (entry, stmt);
+    }
 
-  bvar = SSA_NAME_VAR (name);
-  stmt = build_gimple_modify_stmt (bvar, fold_convert (type, name));
-  name = make_ssa_name (bvar, stmt);
-  GIMPLE_STMT_OPERAND (stmt, 0) = name;
-  bsi_insert_on_edge_immediate (entry, stmt);
+  if (TREE_TYPE (name) != type)
+    {
+      name = force_gimple_operand (fold_convert (type, name), &stmt, true,
+                                  NULL_TREE);
+      if (stmt)
+       bsi_insert_on_edge_immediate (entry, stmt);
+    }
 
   return name;
 }
@@ -490,13 +523,11 @@ take_address_of (tree var, tree type, struct loop *loop, htab_t decl_address)
 static int
 initialize_reductions (void **slot, void *data)
 {
-  tree stmt;
   tree init, c;
-  tree name1;
   tree bvar, type, arg;
   edge e;
 
-  struct reduction_info *reduc = *slot;
+  struct reduction_info *const reduc = (struct reduction_info *) *slot;
   struct loop *loop = (struct loop *) data;
 
   /* Create initialization in preheader: 
@@ -529,39 +560,31 @@ initialize_reductions (void **slot, void *data)
   e = loop_preheader_edge (loop);
   arg = PHI_ARG_DEF_FROM_EDGE (reduc->reduc_phi, e);
   /* Create new variable to hold the initial value.  */
-  type = TREE_TYPE (bvar);
-  bvar = create_tmp_var (type, "reduction_initial");
-  add_referenced_var (bvar);
-
-  stmt = build_gimple_modify_stmt (bvar, arg);
-  name1 = make_ssa_name (bvar, stmt);
-  GIMPLE_STMT_OPERAND (stmt, 0) = name1;
-  SSA_NAME_DEF_STMT (name1) = stmt;
 
-  bsi_insert_on_edge_immediate (e, stmt);
   SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE
           (reduc->reduc_phi, loop_preheader_edge (loop)), init);
-  reduc->initial_value = name1;
+  reduc->initial_value = arg;
   return 1;
 }
 
 struct elv_data
 {
-  struct loop *loop;
+  edge entry;
   htab_t decl_address;
   bool changed;
 };
 
-/* Eliminates references to local variables in *TP out of LOOP.  DECL_ADDRESS
-   contains addresses of the references that had their address taken already.
-   If the expression is changed, CHANGED is set to true.  Callback for
-   walk_tree.  */
+/* Eliminates references to local variables in *TP out of the single
+   entry single exit region starting at DTA->ENTRY.
+   DECL_ADDRESS contains addresses of the references that had their
+   address taken already.  If the expression is changed, CHANGED is
+   set to true.  Callback for walk_tree.  */
 
 static tree
-eliminate_local_variables_1 (tree * tp, int *walk_subtrees, void *data)
+eliminate_local_variables_1 (tree *tp, int *walk_subtrees, void *data)
 {
-  struct elv_data *dta = data;
-  tree t = *tp, var, addr, addr_type, type;
+  struct elv_data *const dta = (struct elv_data *) data;
+  tree t = *tp, var, addr, addr_type, type, obj;
 
   if (DECL_P (t))
     {
@@ -572,7 +595,7 @@ eliminate_local_variables_1 (tree * tp, int *walk_subtrees, void *data)
 
       type = TREE_TYPE (t);
       addr_type = build_pointer_type (type);
-      addr = take_address_of (t, addr_type, dta->loop, dta->decl_address);
+      addr = take_address_of (t, addr_type, dta->entry, dta->decl_address);
       *tp = build1 (INDIRECT_REF, TREE_TYPE (*tp), addr);
 
       dta->changed = true;
@@ -581,16 +604,28 @@ eliminate_local_variables_1 (tree * tp, int *walk_subtrees, void *data)
 
   if (TREE_CODE (t) == ADDR_EXPR)
     {
-      var = TREE_OPERAND (t, 0);
-      if (!DECL_P (var))
+      /* ADDR_EXPR may appear in two contexts:
+        -- as a gimple operand, when the address taken is a function invariant
+        -- as gimple rhs, when the resulting address in not a function
+           invariant
+        We do not need to do anything special in the latter case (the base of
+        the memory reference whose address is taken may be replaced in the
+        DECL_P case).  The former case is more complicated, as we need to
+        ensure that the new address is still a gimple operand.  Thus, it
+        is not sufficient to replace just the base of the memory reference --
+        we need to move the whole computation of the address out of the
+        loop.  */
+      if (!is_gimple_val (t))
        return NULL_TREE;
 
       *walk_subtrees = 0;
-      if (!SSA_VAR_P (var) || DECL_EXTERNAL (var))
+      obj = TREE_OPERAND (t, 0);
+      var = get_base_address (obj);
+      if (!var || !SSA_VAR_P (var) || DECL_EXTERNAL (var))
        return NULL_TREE;
 
       addr_type = TREE_TYPE (t);
-      addr = take_address_of (var, addr_type, dta->loop, dta->decl_address);
+      addr = take_address_of (obj, addr_type, dta->entry, dta->decl_address);
       *tp = addr;
 
       dta->changed = true;
@@ -603,17 +638,18 @@ eliminate_local_variables_1 (tree * tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Moves the references to local variables in STMT from LOOP.  DECL_ADDRESS
-   contains addresses for the references for that we have already taken
-   them.  */
+/* Moves the references to local variables in STMT out of the single
+   entry single exit region starting at ENTRY.  DECL_ADDRESS contains
+   addresses of the references that had their address taken
+   already.  */
 
 static void
-eliminate_local_variables_stmt (struct loop *loop, tree stmt,
+eliminate_local_variables_stmt (edge entry, tree stmt,
                                htab_t decl_address)
 {
   struct elv_data dta;
 
-  dta.loop = loop;
+  dta.entry = entry;
   dta.decl_address = decl_address;
   dta.changed = false;
 
@@ -623,33 +659,75 @@ eliminate_local_variables_stmt (struct loop *loop, tree stmt,
     update_stmt (stmt);
 }
 
-/* Eliminates the references to local variables from LOOP.  
+/* Eliminates the references to local variables from the single entry
+   single exit region between the ENTRY and EXIT edges.
+  
    This includes:
    1) Taking address of a local variable -- these are moved out of the 
-   loop (and temporary variable is created to hold the address if 
+   region (and temporary variable is created to hold the address if 
    necessary).
+
    2) Dereferencing a local variable -- these are replaced with indirect
    references.  */
 
 static void
-eliminate_local_variables (struct loop *loop)
+eliminate_local_variables (edge entry, edge exit)
 {
-  basic_block bb, *body = get_loop_body (loop);
+  basic_block bb;
+  VEC (basic_block, heap) *body = VEC_alloc (basic_block, heap, 3);
   unsigned i;
   block_stmt_iterator bsi;
   htab_t decl_address = htab_create (10, int_tree_map_hash, int_tree_map_eq,
                                     free);
+  basic_block entry_bb = entry->src;
+  basic_block exit_bb = exit->dest;
 
-  /* Find and rename the ssa names defined outside of loop.  */
-  for (i = 0; i < loop->num_nodes; i++)
-    {
-      bb = body[i];
+  gather_blocks_in_sese_region (entry_bb, exit_bb, &body);
 
+  for (i = 0; VEC_iterate (basic_block, body, i, bb); i++)
+    if (bb != entry_bb && bb != exit_bb)
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       eliminate_local_variables_stmt (loop, bsi_stmt (bsi), decl_address);
-    }
+       eliminate_local_variables_stmt (entry, bsi_stmt (bsi),
+                                       decl_address);
 
   htab_delete (decl_address);
+  VEC_free (basic_block, heap, body);
+}
+
+/* Returns true if expression EXPR is not defined between ENTRY and
+   EXIT, i.e. if all its operands are defined outside of the region.  */
+
+static bool
+expr_invariant_in_region_p (edge entry, edge exit, tree expr)
+{
+  basic_block entry_bb = entry->src;
+  basic_block exit_bb = exit->dest;
+  basic_block def_bb;
+  unsigned i, len;
+
+  if (is_gimple_min_invariant (expr))
+    return true;
+
+  if (TREE_CODE (expr) == SSA_NAME)
+    {
+      def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (expr));
+      if (def_bb
+         && dominated_by_p (CDI_DOMINATORS, def_bb, entry_bb)
+         && !dominated_by_p (CDI_DOMINATORS, def_bb, exit_bb))
+       return false;
+
+      return true;
+    }
+
+  if (!EXPR_P (expr) && !GIMPLE_STMT_P (expr))
+    return false;
+
+  len = TREE_OPERAND_LENGTH (expr);
+  for (i = 0; i < len; i++)
+    if (!expr_invariant_in_region_p (entry, exit, TREE_OPERAND (expr, i)))
+      return false;
+
+  return true;
 }
 
 /* If COPY_NAME_P is true, creates and returns a duplicate of NAME.
@@ -660,9 +738,9 @@ eliminate_local_variables (struct loop *loop)
    duplicated, storing the copies in DECL_COPIES.  */
 
 static tree
-separate_decls_in_loop_name (tree name,
-                            htab_t name_copies, htab_t decl_copies,
-                            bool copy_name_p)
+separate_decls_in_region_name (tree name,
+                              htab_t name_copies, htab_t decl_copies,
+                              bool copy_name_p)
 {
   tree copy, var, var_copy;
   unsigned idx, uid, nuid;
@@ -687,6 +765,7 @@ separate_decls_in_loop_name (tree name,
   if (!*dslot)
     {
       var_copy = create_tmp_var (TREE_TYPE (var), get_name (var));
+      DECL_GIMPLE_REG_P (var_copy) = DECL_GIMPLE_REG_P (var);
       add_referenced_var (var_copy);
       nielt = XNEW (struct int_tree_map);
       nielt->uid = uid;
@@ -726,15 +805,16 @@ separate_decls_in_loop_name (tree name,
   return copy;
 }
 
-/* Finds the ssa names used in STMT that are defined outside of LOOP and
-   replaces such ssa names with their duplicates.  The duplicates are stored to
-   NAME_COPIES.  Base decls of all ssa names used in STMT
-   (including those defined in LOOP) are replaced with the new temporary
-   variables; the replacement decls are stored in DECL_COPIES.  */
+/* Finds the ssa names used in STMT that are defined outside the
+   region between ENTRY and EXIT and replaces such ssa names with
+   their duplicates.  The duplicates are stored to NAME_COPIES.  Base
+   decls of all ssa names used in STMT (including those defined in
+   LOOP) are replaced with the new temporary variables; the
+   replacement decls are stored in DECL_COPIES.  */
 
 static void
-separate_decls_in_loop_stmt (struct loop *loop, tree stmt,
-                            htab_t name_copies, htab_t decl_copies)
+separate_decls_in_region_stmt (edge entry, edge exit, tree stmt,
+                              htab_t name_copies, htab_t decl_copies)
 {
   use_operand_p use;
   def_operand_p def;
@@ -748,8 +828,8 @@ separate_decls_in_loop_stmt (struct loop *loop, tree stmt,
   {
     name = DEF_FROM_PTR (def);
     gcc_assert (TREE_CODE (name) == SSA_NAME);
-    copy = separate_decls_in_loop_name (name, name_copies, decl_copies,
-                                       false);
+    copy = separate_decls_in_region_name (name, name_copies, decl_copies,
+                                         false);
     gcc_assert (copy == name);
   }
 
@@ -759,9 +839,9 @@ separate_decls_in_loop_stmt (struct loop *loop, tree stmt,
     if (TREE_CODE (name) != SSA_NAME)
       continue;
 
-    copy_name_p = expr_invariant_in_loop_p (loop, name);
-    copy = separate_decls_in_loop_name (name, name_copies, decl_copies,
-                                       copy_name_p);
+    copy_name_p = expr_invariant_in_region_p (entry, exit, name);
+    copy = separate_decls_in_region_name (name, name_copies, decl_copies,
+                                         copy_name_p);
     SET_USE (use, copy);
   }
 }
@@ -773,8 +853,8 @@ static int
 add_field_for_reduction (void **slot, void *data)
 {
   
-  struct reduction_info *red = *slot;
-  tree type = data;
+  struct reduction_info *const red = (struct reduction_info *) *slot;
+  tree const type = (tree) data;
   tree var = SSA_NAME_VAR (GIMPLE_STMT_OPERAND (red->reduc_stmt, 0));
   tree field = build_decl (FIELD_DECL, DECL_NAME (var), TREE_TYPE (var));
 
@@ -791,8 +871,8 @@ add_field_for_reduction (void **slot, void *data)
 static int
 add_field_for_name (void **slot, void *data)
 {
-  struct name_to_copy_elt *elt = *slot;
-  tree type = data;
+  struct name_to_copy_elt *const elt = (struct name_to_copy_elt *) *slot;
+  tree type = (tree) data;
   tree name = ssa_name (elt->version);
   tree var = SSA_NAME_VAR (name);
   tree field = build_decl (FIELD_DECL, DECL_NAME (var), TREE_TYPE (var));
@@ -805,7 +885,7 @@ add_field_for_name (void **slot, void *data)
 
 /* Callback for htab_traverse.  A local result is the intermediate result 
    computed by a single 
-   thread, or the intial value in case no iteration was executed.
+   thread, or the initial value in case no iteration was executed.
    This function creates a phi node reflecting these values.  
    The phi's result will be stored in NEW_PHI field of the 
    reduction's data structure.  */ 
@@ -813,8 +893,8 @@ add_field_for_name (void **slot, void *data)
 static int
 create_phi_for_local_result (void **slot, void *data)
 {
-  struct reduction_info *reduc = *slot;
-  struct loop *loop = data;
+  struct reduction_info *const reduc = (struct reduction_info *) *slot;
+  const struct loop *const loop = (const struct loop *) data;
   edge e;
   tree new_phi;
   basic_block store_bb;
@@ -862,8 +942,8 @@ struct clsn_data
 static int
 create_call_for_reduction_1 (void **slot, void *data)
 {
-  struct reduction_info *reduc = *slot;
-  struct clsn_data *clsn_data = data;
+  struct reduction_info *const reduc = (struct reduction_info *) *slot;
+  struct clsn_data *const clsn_data = (struct clsn_data *) data;
   block_stmt_iterator bsi;
   tree type = TREE_TYPE (PHI_RESULT (reduc->reduc_phi));
   tree struct_type = TREE_TYPE (TREE_TYPE (clsn_data->load));
@@ -927,44 +1007,28 @@ create_call_for_reduction (struct loop *loop, htab_t reduction_list,
   htab_traverse (reduction_list, create_call_for_reduction_1, ld_st_data);
 }
 
-/* Callback for htab_traverse.  Create a new variable that loads the 
-   final reduction value at the  
-   join point of all threads, adds the initial value the reduction 
-   variable had before the parallel computation started, and 
-   inserts it in the right place.  */
+/* Callback for htab_traverse.  Loads the final reduction value at the
+   join point of all threads, and inserts it in the right place.  */
 
 static int
 create_loads_for_reductions (void **slot, void *data)
 {
-  struct reduction_info *red = *slot;
-  struct clsn_data *clsn_data = data;
+  struct reduction_info *const red = (struct reduction_info *) *slot;
+  struct clsn_data *const clsn_data = (struct clsn_data *) data;
   tree stmt;
   block_stmt_iterator bsi;
   tree type = TREE_TYPE (GIMPLE_STMT_OPERAND (red->reduc_stmt, 0));
   tree struct_type = TREE_TYPE (TREE_TYPE (clsn_data->load));
   tree load_struct;
-  tree bvar, name;
+  tree name;
   tree x;
 
   bsi = bsi_after_labels (clsn_data->load_bb);
   load_struct = fold_build1 (INDIRECT_REF, struct_type, clsn_data->load);
   load_struct = build3 (COMPONENT_REF, type, load_struct, red->field,
                        NULL_TREE);
-  bvar = create_tmp_var (type, "reduction_final");
-  add_referenced_var (bvar);
-
-  /* Apply operation between the new variable which is the result
-     of computation all threads, and the initial value which is kept
-     at reduction->inital_value.  */
 
-  stmt = build_gimple_modify_stmt (bvar, load_struct);
-  name = make_ssa_name (bvar, stmt);
-  GIMPLE_STMT_OPERAND (stmt, 0) = name;
-  SSA_NAME_DEF_STMT (name) = stmt;
-  bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
-  x =
-    fold_build2 (red->reduction_code, TREE_TYPE (load_struct),
-                name, red->initial_value);
+  x = load_struct;
   name = PHI_RESULT (red->keep_res);
   stmt = build_gimple_modify_stmt (name, x);
   GIMPLE_STMT_OPERAND (stmt, 0) = name;
@@ -979,7 +1043,7 @@ create_loads_for_reductions (void **slot, void *data)
 
 /* Load the reduction result that was stored in LD_ST_DATA.  
    REDUCTION_LIST describes the list of reductions that the
-   loades should be generated for.  */
+   loads should be generated for.  */
 static void
 create_final_loads_for_reduction (htab_t reduction_list, 
                                  struct clsn_data *ld_st_data)
@@ -1010,8 +1074,8 @@ create_final_loads_for_reduction (htab_t reduction_list,
 static int
 create_stores_for_reduction (void **slot, void *data)
 {
-  struct reduction_info *red = *slot;
-  struct clsn_data *clsn_data = data;
+  struct reduction_info *const red = (struct reduction_info *) *slot;
+  struct clsn_data *const clsn_data = (struct clsn_data *) data;
   tree stmt;
   block_stmt_iterator bsi;
   tree type = TREE_TYPE (GIMPLE_STMT_OPERAND (red->reduc_stmt, 0));
@@ -1021,7 +1085,7 @@ create_stores_for_reduction (void **slot, void *data)
     build_gimple_modify_stmt (build3
                               (COMPONENT_REF, type, clsn_data->store,
                                red->field, NULL_TREE),
-                               red->init );
+                               red->initial_value);
   mark_virtual_ops_for_renaming (stmt);
   bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
 
@@ -1035,8 +1099,8 @@ create_stores_for_reduction (void **slot, void *data)
 static int
 create_loads_and_stores_for_name (void **slot, void *data)
 {
-  struct name_to_copy_elt *elt = *slot;
-  struct clsn_data *clsn_data = data;
+  struct name_to_copy_elt *const elt = (struct name_to_copy_elt *) *slot;
+  struct clsn_data *const clsn_data = (struct clsn_data *) data;
   tree stmt;
   block_stmt_iterator bsi;
   tree type = TREE_TYPE (elt->new_name);
@@ -1098,36 +1162,44 @@ create_loads_and_stores_for_name (void **slot, void *data)
    in LOOP.  */
 
 static void
-separate_decls_in_loop (struct loop *loop, htab_t reduction_list, 
-                       tree * arg_struct, tree * new_arg_struct, 
-                       struct clsn_data *ld_st_data)
+separate_decls_in_region (edge entry, edge exit, htab_t reduction_list,
+                         tree *arg_struct, tree *new_arg_struct, 
+                         struct clsn_data *ld_st_data)
 
 {
-  basic_block bb1 = split_edge (loop_preheader_edge (loop));
+  basic_block bb1 = split_edge (entry);
   basic_block bb0 = single_pred (bb1);
   htab_t name_copies = htab_create (10, name_to_copy_elt_hash,
                                    name_to_copy_elt_eq, free);
   htab_t decl_copies = htab_create (10, int_tree_map_hash, int_tree_map_eq,
                                    free);
-  basic_block bb, *body = get_loop_body (loop);
   unsigned i;
   tree phi, type, type_name, nvar;
   block_stmt_iterator bsi;
   struct clsn_data clsn_data;
+  VEC (basic_block, heap) *body = VEC_alloc (basic_block, heap, 3);
+  basic_block bb;
+  basic_block entry_bb = bb1;
+  basic_block exit_bb = exit->dest;
 
-  /* Find and rename the ssa names defined outside of loop.  */
-  for (i = 0; i < loop->num_nodes; i++)
-    {
-      bb = body[i];
-
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       separate_decls_in_loop_stmt (loop, phi, name_copies, decl_copies);
+  entry = single_succ_edge(entry_bb);
+  gather_blocks_in_sese_region (entry_bb, exit_bb, &body);
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       separate_decls_in_loop_stmt (loop, bsi_stmt (bsi), name_copies,
-                                    decl_copies);
+  for (i = 0; VEC_iterate (basic_block, body, i, bb); i++)
+    {
+      if (bb != entry_bb && bb != exit_bb) 
+       {
+         for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+           separate_decls_in_region_stmt (entry, exit, phi, name_copies,
+                                          decl_copies);
+         
+         for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+           separate_decls_in_region_stmt (entry, exit, bsi_stmt (bsi),
+                                          name_copies, decl_copies);
+       }
     }
-  free (body);
+
+  VEC_free (basic_block, heap, body);
 
   if (htab_elements (name_copies) == 0)
     {
@@ -1145,7 +1217,7 @@ separate_decls_in_loop (struct loop *loop, htab_t reduction_list,
       TYPE_NAME (type) = type_name;
 
       htab_traverse (name_copies, add_field_for_name, type);
-      if (htab_elements (reduction_list) > 0)
+      if (reduction_list && htab_elements (reduction_list) > 0)
        {
          /* Create the fields for reductions.  */
          htab_traverse (reduction_list, add_field_for_reduction,
@@ -1168,14 +1240,14 @@ separate_decls_in_loop (struct loop *loop, htab_t reduction_list,
       htab_traverse (name_copies, create_loads_and_stores_for_name,
                     ld_st_data);
 
-      /* Load the calculation from memory into a new 
-         reduction variable (after the join of the threads).  */
-      if (htab_elements (reduction_list) > 0)
+      /* Load the calculation from memory (after the join of the threads).  */
+
+      if (reduction_list && htab_elements (reduction_list) > 0)
        {
          htab_traverse (reduction_list, create_stores_for_reduction,
                         ld_st_data); 
          clsn_data.load = make_ssa_name (nvar, NULL_TREE);
-         clsn_data.load_bb = single_dom_exit (loop)->dest;
+         clsn_data.load_bb = exit->dest;
          clsn_data.store = ld_st_data->store;
          create_final_loads_for_reduction (reduction_list, &clsn_data);
        }
@@ -1248,11 +1320,11 @@ create_loop_fn (void)
   TREE_USED (t) = 1;
   DECL_ARGUMENTS (decl) = t;
 
-  allocate_struct_function (decl);
+  allocate_struct_function (decl, false);
 
   /* The call to allocate_struct_function clobbers CFUN, so we need to restore
      it.  */
-  cfun = act_cfun;
+  set_cfun (act_cfun);
 
   return decl;
 }
@@ -1266,7 +1338,7 @@ static void
 canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit)
 {
   unsigned precision = TYPE_PRECISION (TREE_TYPE (nit));
-  tree phi, prev, res, type, var_before, val, atype, t, next;
+  tree phi, prev, res, type, var_before, val, atype, mtype, t, next;
   block_stmt_iterator bsi;
   bool ok;
   affine_iv iv;
@@ -1313,11 +1385,12 @@ canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit)
       remove_phi_node (phi, prev, false);
 
       atype = TREE_TYPE (res);
-      val = fold_build2 (PLUS_EXPR, atype,
-                        unshare_expr (iv.base),
-                        fold_build2 (MULT_EXPR, atype,
-                                     unshare_expr (iv.step),
-                                     fold_convert (atype, var_before)));
+      mtype = POINTER_TYPE_P (atype) ? sizetype : atype;
+      val = fold_build2 (MULT_EXPR, mtype, unshare_expr (iv.step),
+                        fold_convert (mtype, var_before));
+      val = fold_build2 (POINTER_TYPE_P (atype)
+                        ? POINTER_PLUS_EXPR : PLUS_EXPR,
+                        atype, unshare_expr (iv.base), val);
       val = force_gimple_operand_bsi (&bsi, val, false, NULL_TREE, true,
                                      BSI_SAME_STMT);
       t = build_gimple_modify_stmt (res, val);
@@ -1343,7 +1416,7 @@ canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit)
    exit of the loop.  NIT is the number of iterations of the loop
    (used to initialize the variables in the duplicated part).
  
-   TODO: the common case is that latch of the loop is empty and immediatelly
+   TODO: the common case is that latch of the loop is empty and immediately
    follows the loop exit.  In this case, it would be better not to copy the
    body of the loop, but only move the entry of the loop directly before the
    exit check and increase the number of iterations of the loop by one.
@@ -1438,6 +1511,9 @@ transform_to_exit_first_loop (struct loop *loop, htab_t reduction_list, tree nit
 
   /* Initialize the control variable to NIT.  */
   bsi = bsi_after_labels (ex_bb);
+  nit = force_gimple_operand_bsi (&bsi,
+                                 fold_convert (TREE_TYPE (control_name), nit),
+                                 false, NULL_TREE, false, BSI_SAME_STMT);
   t = build_gimple_modify_stmt (control_name, nit);
   bsi_insert_before (&bsi, t, BSI_NEW_STMT);
   SSA_NAME_DEF_STMT (control_name) = t;
@@ -1541,13 +1617,16 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data,
   for_stmt = make_node (OMP_FOR);
   TREE_TYPE (for_stmt) = void_type_node;
   OMP_FOR_CLAUSES (for_stmt) = t;
-  OMP_FOR_INIT (for_stmt) = build_gimple_modify_stmt (initvar, cvar_init);
-  OMP_FOR_COND (for_stmt) = cond;
-  OMP_FOR_INCR (for_stmt) = build_gimple_modify_stmt (cvar_base,
-                                                     build2 (PLUS_EXPR, type,
-                                                             cvar_base,
-                                                             build_int_cst
-                                                             (type, 1)));
+  OMP_FOR_INIT (for_stmt) = make_tree_vec (1);
+  TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), 0)
+    = build_gimple_modify_stmt (initvar, cvar_init);
+  OMP_FOR_COND (for_stmt) = make_tree_vec (1);
+  TREE_VEC_ELT (OMP_FOR_COND (for_stmt), 0) = cond;
+  OMP_FOR_INCR (for_stmt) = make_tree_vec (2);
+  TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), 0)
+    = build_gimple_modify_stmt (cvar_base,
+                               build2 (PLUS_EXPR, type, cvar_base,
+                                       build_int_cst (type, 1)));
   OMP_FOR_BODY (for_stmt) = NULL_TREE;
   OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE;
 
@@ -1563,23 +1642,27 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data,
 
   /* Emit OMP_RETURN for OMP_FOR.  */
   bsi = bsi_last (ex_bb);
-  bsi_insert_after (&bsi, make_node (OMP_RETURN), BSI_NEW_STMT);
+  t = make_node (OMP_RETURN);
+  OMP_RETURN_NOWAIT (t) = 1;
+  bsi_insert_after (&bsi, t, BSI_NEW_STMT);
 
   return paral_bb;
 }
 
 /* Generates code to execute the iterations of LOOP in N_THREADS threads in
    parallel.  NITER describes number of iterations of LOOP.  
-   REDUCTION_LIST describes the reductions existant in the LOOP.  */
+   REDUCTION_LIST describes the reductions existent in the LOOP.  */
 
 static void
 gen_parallel_loop (struct loop *loop, htab_t reduction_list, 
                   unsigned n_threads, struct tree_niter_desc *niter)
 {
   struct loop *nloop;
+  loop_iterator li;
   tree many_iterations_cond, type, nit;
   tree stmts, arg_struct, new_arg_struct;
   basic_block parallel_head;
+  edge entry, exit;
   struct clsn_data clsn_data;
   unsigned prob;
 
@@ -1677,18 +1760,20 @@ gen_parallel_loop (struct loop *loop, htab_t reduction_list,
   /* Ensure that the exit condition is the first statement in the loop.  */
   transform_to_exit_first_loop (loop, reduction_list, nit);
 
-
-  /* Generate intializations for reductions.  */
-
+  /* Generate initializations for reductions.  */
   if (htab_elements (reduction_list) > 0)  
     htab_traverse (reduction_list, initialize_reductions, loop);
 
   /* Eliminate the references to local variables from the loop.  */
-  eliminate_local_variables (loop);
+  gcc_assert (single_exit (loop));
+  entry = loop_preheader_edge (loop);
+  exit = single_dom_exit (loop);
 
+  eliminate_local_variables (entry, exit);
   /* In the old loop, move all variables non-local to the loop to a structure
      and back, and create separate decls for the variables used in loop.  */
-  separate_decls_in_loop (loop, reduction_list, &arg_struct, &new_arg_struct, &clsn_data);
+  separate_decls_in_region (entry, exit, reduction_list, &arg_struct, 
+                           &new_arg_struct, &clsn_data);
 
   /* Create the parallel constructs.  */
   parallel_head = create_parallel_loop (loop, create_loop_fn (), arg_struct,
@@ -1702,6 +1787,11 @@ gen_parallel_loop (struct loop *loop, htab_t reduction_list,
      expander to do it).  */
   cancel_loop_tree (loop);
 
+  /* Free loop bound estimations that could contain references to
+     removed statements.  */
+  FOR_EACH_LOOP (li, loop, 0)
+    free_numbers_of_iterations_estimates_loop (loop);
+
   /* Expand the parallel constructs.  We do it directly here instead of running
      a separate expand_omp pass, since it is more efficient, and less likely to
      cause troubles with further analyses not being able to deal with the
@@ -1710,6 +1800,27 @@ gen_parallel_loop (struct loop *loop, htab_t reduction_list,
   omp_expand_local (parallel_head);
 }
 
+/* Returns true when LOOP contains vector phi nodes.  */
+
+static bool
+loop_has_vector_phi_nodes (struct loop *loop)
+{
+  unsigned i;
+  basic_block *bbs = get_loop_body_in_dom_order (loop);
+  bool res = true;
+  tree phi;
+
+  for (i = 0; i < loop->num_nodes; i++)
+    for (phi = phi_nodes (bbs[i]); phi; phi = PHI_CHAIN (phi))
+      if (TREE_CODE (TREE_TYPE (PHI_RESULT (phi))) == VECTOR_TYPE)
+       goto end;
+
+  res = false;
+ end:
+  free (bbs);
+  return res;
+}
+
 /* Detect parallel loops and generate parallel code using libgomp
    primitives.  Returns true if some loop was parallelized, false
    otherwise.  */
@@ -1740,6 +1851,9 @@ parallelize_loops (void)
          || expected_loop_iterations (loop) <= n_threads
          /* And of course, the loop must be parallelizable.  */
          || !can_duplicate_loop_p (loop)
+         || loop_has_blocks_with_irreducible_flag (loop)
+         /* FIXME: the check for vector phi nodes could be removed.  */
+         || loop_has_vector_phi_nodes (loop)
          || !loop_parallel_p (loop, reduction_list, &niter_desc))
        continue;