+ case GIMPLE_OMP_PARALLEL:
+ case GIMPLE_OMP_TASK:
+ save_suppress = info->suppress_expansion;
+ if (convert_nonlocal_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+ wi))
+ {
+ tree c, decl;
+ decl = get_chain_decl (info);
+ c = build_omp_clause (gimple_location (stmt),
+ OMP_CLAUSE_FIRSTPRIVATE);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+ gimple_omp_taskreg_set_clauses (stmt, c);
+ }
+
+ save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (gimple_omp_body (stmt)),
+ false);
+ info->new_local_var_chain = save_local_var_chain;
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_FOR:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+ walk_gimple_omp_for (stmt, convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info);
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTIONS:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SINGLE:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTION:
+ case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_ORDERED:
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body (stmt));
+ break;
+
+ case GIMPLE_BIND:
+ if (!optimize && gimple_bind_block (stmt))
+ note_nonlocal_block_vlas (info, gimple_bind_block (stmt));
+
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ case GIMPLE_COND:
+ wi->val_only = true;
+ wi->is_lhs = false;
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ default:
+ /* For every other statement that we are not interested in
+ handling here, let the walker traverse the operands. */
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ /* We have handled all of STMT operands, no need to traverse the operands. */
+ *handled_ops_p = true;
+ return NULL_TREE;
+}
+
+
+/* A subroutine of convert_local_reference. Create a local variable
+ in the parent function with DECL_VALUE_EXPR set to reference the
+ field in FRAME. This is used both for debug info and in OpenMP
+ lowering. */
+
+static tree
+get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
+{
+ tree x, new_decl;
+ void **slot;
+
+ slot = pointer_map_insert (info->var_map, decl);
+ if (*slot)
+ return (tree) *slot;
+
+ /* Make sure frame_decl gets created. */
+ (void) get_frame_type (info);
+ x = info->frame_decl;
+ x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+
+ new_decl = build_decl (DECL_SOURCE_LOCATION (decl),
+ VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+ DECL_CONTEXT (new_decl) = info->context;
+ DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+ DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+ TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+ TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+ TREE_READONLY (new_decl) = TREE_READONLY (decl);
+ TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+ DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+ if ((TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && DECL_BY_REFERENCE (decl))
+ DECL_BY_REFERENCE (new_decl) = 1;
+
+ SET_DECL_VALUE_EXPR (new_decl, x);
+ DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+ *slot = new_decl;
+
+ TREE_CHAIN (new_decl) = info->debug_var_chain;
+ info->debug_var_chain = new_decl;
+
+ /* Do not emit debug info twice. */
+ DECL_IGNORED_P (decl) = 1;
+
+ return new_decl;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all references to VAR
+ and PARM_DECLs that were referenced by inner nested functions.
+ The rewrite will be a structure reference to the local frame variable. */
+
+static bool convert_local_omp_clauses (tree *, struct walk_stmt_info *);
+
+static tree
+convert_local_reference_op (tree *tp, int *walk_subtrees, void *data)
+{
+ struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+ struct nesting_info *const info = (struct nesting_info *) wi->info;
+ tree t = *tp, field, x;
+ bool save_val_only;
+
+ *walk_subtrees = 0;
+ switch (TREE_CODE (t))
+ {
+ case VAR_DECL:
+ /* Non-automatic variables are never processed. */
+ if (TREE_STATIC (t) || DECL_EXTERNAL (t))
+ break;
+ /* FALLTHRU */
+
+ case PARM_DECL:
+ if (decl_function_context (t) == info->context)
+ {
+ /* If we copied a pointer to the frame, then the original decl
+ is used unchanged in the parent function. */
+ if (use_pointer_in_frame (t))
+ break;
+
+ /* No need to transform anything if no child references the
+ variable. */
+ field = lookup_field_for_decl (info, t, NO_INSERT);
+ if (!field)
+ break;
+ wi->changed = true;
+
+ x = get_local_debug_decl (info, t, field);
+ if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+ x = get_frame_field (info, info->context, field, &wi->gsi);
+
+ if (wi->val_only)
+ {
+ if (wi->is_lhs)
+ x = save_tmp_var (info, x, &wi->gsi);
+ else
+ x = init_tmp_var (info, x, &wi->gsi);
+ }
+
+ *tp = x;
+ }
+ break;
+
+ case ADDR_EXPR:
+ save_val_only = wi->val_only;
+ wi->val_only = false;
+ wi->is_lhs = false;
+ wi->changed = false;
+ walk_tree (&TREE_OPERAND (t, 0), convert_local_reference_op, wi, NULL);
+ wi->val_only = save_val_only;
+
+ /* If we converted anything ... */
+ if (wi->changed)
+ {
+ tree save_context;
+
+ /* Then the frame decl is now addressable. */
+ TREE_ADDRESSABLE (info->frame_decl) = 1;
+
+ save_context = current_function_decl;
+ current_function_decl = info->context;
+ recompute_tree_invariant_for_addr_expr (t);
+ current_function_decl = save_context;
+
+ /* If we are in a context where we only accept values, then
+ compute the address into a temporary. */
+ if (save_val_only)
+ *tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
+ t, &wi->gsi);
+ }
+ break;
+
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ case BIT_FIELD_REF:
+ /* Go down this entire nest and just look at the final prefix and
+ anything that describes the references. Otherwise, we lose track
+ of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
+ save_val_only = wi->val_only;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
+ {
+ if (TREE_CODE (t) == COMPONENT_REF)
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
+ NULL);
+ else if (TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 3), convert_local_reference_op, wi,
+ NULL);
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
+ NULL);
+ }
+ }
+ wi->val_only = false;
+ walk_tree (tp, convert_local_reference_op, wi, NULL);
+ wi->val_only = save_val_only;
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ /* Just request to look at the subtrees, leaving val_only and lhs
+ untouched. This might actually be for !val_only + lhs, in which
+ case we don't want to force a replacement by a temporary. */
+ *walk_subtrees = 1;
+ break;
+
+ default:
+ if (!IS_TYPE_OR_DECL_P (t))
+ {
+ *walk_subtrees = 1;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ }
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+static tree convert_local_reference_stmt (gimple_stmt_iterator *, bool *,
+ struct walk_stmt_info *);
+
+/* Helper for convert_local_reference. Convert all the references in
+ the chain of clauses at *PCLAUSES. WI is as in convert_local_reference. */
+
+static bool
+convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+ struct nesting_info *const info = (struct nesting_info *) wi->info;
+ bool need_frame = false, need_stmts = false;
+ tree clause, decl;
+ int dummy;
+ bitmap new_suppress;
+
+ new_suppress = BITMAP_GGC_ALLOC ();
+ bitmap_copy (new_suppress, info->suppress_expansion);
+
+ for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+ {
+ switch (OMP_CLAUSE_CODE (clause))
+ {
+ case OMP_CLAUSE_REDUCTION:
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+ need_stmts = true;
+ goto do_decl_clause;
+
+ case OMP_CLAUSE_LASTPRIVATE:
+ if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause))
+ need_stmts = true;
+ goto do_decl_clause;
+
+ case OMP_CLAUSE_PRIVATE:
+ case OMP_CLAUSE_FIRSTPRIVATE:
+ case OMP_CLAUSE_COPYPRIVATE:
+ case OMP_CLAUSE_SHARED:
+ do_decl_clause:
+ decl = OMP_CLAUSE_DECL (clause);
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ break;
+ if (decl_function_context (decl) == info->context
+ && !use_pointer_in_frame (decl))
+ {
+ tree field = lookup_field_for_decl (info, decl, NO_INSERT);
+ if (field)
+ {
+ bitmap_set_bit (new_suppress, DECL_UID (decl));
+ OMP_CLAUSE_DECL (clause)
+ = get_local_debug_decl (info, decl, field);
+ need_frame = true;
+ }
+ }
+ break;
+
+ case OMP_CLAUSE_SCHEDULE:
+ if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
+ break;
+ /* FALLTHRU */
+ case OMP_CLAUSE_IF:
+ case OMP_CLAUSE_NUM_THREADS:
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
+ wi);
+ break;
+
+ case OMP_CLAUSE_NOWAIT:
+ case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_DEFAULT:
+ case OMP_CLAUSE_COPYIN:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_UNTIED:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ info->suppress_expansion = new_suppress;
+
+ if (need_stmts)
+ for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+ switch (OMP_CLAUSE_CODE (clause))
+ {
+ case OMP_CLAUSE_REDUCTION:
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+ {
+ tree old_context
+ = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+ = info->context;
+ walk_body (convert_local_reference_stmt,
+ convert_local_reference_op, info,
+ OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+ walk_body (convert_local_reference_stmt,
+ convert_local_reference_op, info,
+ OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+ = old_context;
+ }
+ break;
+
+ case OMP_CLAUSE_LASTPRIVATE:
+ walk_body (convert_local_reference_stmt,
+ convert_local_reference_op, info,
+ OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ break;
+
+ default:
+ break;
+ }
+
+ return need_frame;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all references to VAR
+ and PARM_DECLs that were referenced by inner nested functions.
+ The rewrite will be a structure reference to the local frame variable. */
+
+static tree
+convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+ struct walk_stmt_info *wi)
+{
+ struct nesting_info *info = (struct nesting_info *) wi->info;
+ tree save_local_var_chain;
+ bitmap save_suppress;
+ gimple stmt = gsi_stmt (*gsi);
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_OMP_PARALLEL:
+ case GIMPLE_OMP_TASK:
+ save_suppress = info->suppress_expansion;
+ if (convert_local_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+ wi))
+ {
+ tree c;
+ (void) get_frame_type (info);
+ c = build_omp_clause (gimple_location (stmt),
+ OMP_CLAUSE_SHARED);
+ OMP_CLAUSE_DECL (c) = info->frame_decl;
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+ gimple_omp_taskreg_set_clauses (stmt, c);
+ }
+
+ save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+
+ walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
+ gimple_omp_body (stmt));
+
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (gimple_omp_body (stmt)), false);
+ info->new_local_var_chain = save_local_var_chain;
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_FOR:
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+ walk_gimple_omp_for (stmt, convert_local_reference_stmt,
+ convert_local_reference_op, info);
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTIONS:
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SINGLE:
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_SECTION:
+ case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_ORDERED:
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body (stmt));
+ break;
+
+ case GIMPLE_COND:
+ wi->val_only = true;
+ wi->is_lhs = false;
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ default:
+ /* For every other statement that we are not interested in
+ handling here, let the walker traverse the operands. */
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ /* Indicate that we have handled all the operands ourselves. */
+ *handled_ops_p = true;
+ return NULL_TREE;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_GOTOs
+ that reference labels from outer functions. The rewrite will be a
+ call to __builtin_nonlocal_goto. */
+
+static tree
+convert_nl_goto_reference (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+ struct walk_stmt_info *wi)
+{
+ struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+ tree label, new_label, target_context, x, field;
+ void **slot;
+ gimple call;
+ gimple stmt = gsi_stmt (*gsi);
+
+ if (gimple_code (stmt) != GIMPLE_GOTO)
+ {
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ label = gimple_goto_dest (stmt);
+ if (TREE_CODE (label) != LABEL_DECL)
+ {
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ target_context = decl_function_context (label);
+ if (target_context == info->context)
+ {
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+
+ for (i = info->outer; target_context != i->context; i = i->outer)
+ continue;