*stmt_p = genericize_spaceship (*stmt_p);
break;
- genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+ case OMP_DISTRIBUTE:
+ /* Need to explicitly instantiate copy ctors on class iterators of
+ composite distribute parallel for. */
+ if (OMP_FOR_INIT (*stmt_p) == NULL_TREE)
+ {
+ tree *data[4] = { NULL, NULL, NULL, NULL };
+ tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p),
+ find_combined_omp_for, data, NULL);
+ if (inner != NULL_TREE
+ && TREE_CODE (inner) == OMP_FOR)
+ {
+ for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++)
+ if (OMP_FOR_ORIG_DECLS (inner)
+ && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
+ i)) == TREE_LIST
+ && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
+ i)))
+ {
+ tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i);
+ /* Class iterators aren't allowed on OMP_SIMD, so the only
+ case we need to solve is distribute parallel for. */
+ gcc_assert (TREE_CODE (inner) == OMP_FOR
+ && data[1]);
+ tree orig_decl = TREE_PURPOSE (orig);
+ tree c, cl = NULL_TREE;
+ for (c = OMP_FOR_CLAUSES (inner);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+ && OMP_CLAUSE_DECL (c) == orig_decl)
+ {
+ cl = c;
+ break;
+ }
+ if (cl == NULL_TREE)
+ {
+ for (c = OMP_PARALLEL_CLAUSES (*data[1]);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+ && OMP_CLAUSE_DECL (c) == orig_decl)
+ {
+ cl = c;
+ break;
+ }
+ }
+ if (cl)
+ {
+ orig_decl = require_complete_type (orig_decl);
+ tree inner_type = TREE_TYPE (orig_decl);
+ if (orig_decl == error_mark_node)
+ continue;
+ if (TYPE_REF_P (TREE_TYPE (orig_decl)))
+ inner_type = TREE_TYPE (inner_type);
+
+ while (TREE_CODE (inner_type) == ARRAY_TYPE)
+ inner_type = TREE_TYPE (inner_type);
+ get_copy_ctor (inner_type, tf_warning_or_error);
+ }
+ }
+ }
+ }
+ /* FALLTHRU */
++ case FOR_STMT:
++ case WHILE_STMT:
++ case DO_STMT:
++ case SWITCH_STMT:
++ case CONTINUE_STMT:
++ case BREAK_STMT:
+ case OMP_FOR:
+ case OMP_SIMD:
+ case OMP_LOOP:
+ case OACC_LOOP:
++ /* These cases are handled by shared code. */
++ c_genericize_control_stmt (stmt_p, walk_subtrees, data,
++ cp_genericize_r, cp_walk_subtrees);
+ break;
+
case PTRMEM_CST:
/* By the time we get here we're handing off to the back end, so we don't
need or want to preserve PTRMEM_CST anymore. */
*expr_p = NULL_TREE;
}
- /* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD
- with non-NULL OMP_FOR_INIT. Also, fill in pdata array,
- pdata[0] non-NULL if there is anything non-trivial in between, pdata[1]
- is address of OMP_PARALLEL in between if any, pdata[2] is address of
- OMP_FOR in between if any and pdata[3] is address of the inner
- OMP_FOR/OMP_SIMD. */
-
- static tree
- find_combined_omp_for (tree *tp, int *walk_subtrees, void *data)
- {
- tree **pdata = (tree **) data;
- *walk_subtrees = 0;
- switch (TREE_CODE (*tp))
- {
- case OMP_FOR:
- if (OMP_FOR_INIT (*tp) != NULL_TREE)
- {
- pdata[3] = tp;
- return *tp;
- }
- pdata[2] = tp;
- *walk_subtrees = 1;
- break;
- case OMP_SIMD:
- if (OMP_FOR_INIT (*tp) != NULL_TREE)
- {
- pdata[3] = tp;
- return *tp;
- }
- break;
- case BIND_EXPR:
- if (BIND_EXPR_VARS (*tp)
- || (BIND_EXPR_BLOCK (*tp)
- && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
- pdata[0] = tp;
- *walk_subtrees = 1;
- break;
- case STATEMENT_LIST:
- if (!tsi_one_before_end_p (tsi_start (*tp)))
- pdata[0] = tp;
- *walk_subtrees = 1;
- break;
- case TRY_FINALLY_EXPR:
- pdata[0] = tp;
- *walk_subtrees = 1;
- break;
- case OMP_PARALLEL:
- pdata[1] = tp;
- *walk_subtrees = 1;
- break;
- default:
- break;
- }
- return NULL_TREE;
- }
-
+/* Helper function for localize_reductions. Replace all uses of REF_VAR with
+ LOCAL_VAR. */
+
+static tree
+localize_reductions_r (tree *tp, int *walk_subtrees, void *data)
+{
+ enum tree_code tc = TREE_CODE (*tp);
+ struct privatize_reduction *pr = (struct privatize_reduction *) data;
+
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ switch (tc)
+ {
+ case INDIRECT_REF:
+ case MEM_REF:
+ if (TREE_OPERAND (*tp, 0) == pr->ref_var)
+ *tp = pr->local_var;
+
+ *walk_subtrees = 0;
+ break;
+
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ if (*tp == pr->ref_var)
+ *tp = pr->local_var;
+
+ *walk_subtrees = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+/* OpenACC worker and vector loop state propagation requires reductions
+ to be inside local variables. This function replaces all reference-type
+ reductions variables associated with the loop with a local copy. It is
+ also used to create private copies of reduction variables for those
+ which are not associated with acc loops. */
+
+static void
+localize_reductions (tree clauses, tree body)
+{
+ tree c, var, type, new_var;
+ struct privatize_reduction pr;
+
+ for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+ {
+ var = OMP_CLAUSE_DECL (c);
+
+ if (!lang_hooks.decls.omp_privatize_by_reference (var))
+ {
+ OMP_CLAUSE_REDUCTION_PRIVATE_DECL (c) = NULL;
+ continue;
+ }
+
+ type = TREE_TYPE (TREE_TYPE (var));
+ new_var = create_tmp_var (type, IDENTIFIER_POINTER (DECL_NAME (var)));
+
+ pr.ref_var = var;
+ pr.local_var = new_var;
+
+ walk_tree (&body, localize_reductions_r, &pr, NULL);
+
+ OMP_CLAUSE_REDUCTION_PRIVATE_DECL (c) = new_var;
+ }
+ else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE)
+ {
+ var = OMP_CLAUSE_DECL (c);
+
+ if (!lang_hooks.decls.omp_privatize_by_reference (var))
+ continue;
+ type = TREE_TYPE (TREE_TYPE (var));
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ continue;
+ new_var = create_tmp_var (type, IDENTIFIER_POINTER (DECL_NAME (var)));
+
+ pr.ref_var = var;
+ pr.local_var = new_var;
+
+ walk_tree (&body, localize_reductions_r, &pr, NULL);
+ }
+}
+
+
/* Gimplify the gross structure of an OMP_FOR statement. */
static enum gimplify_status