+static tree convert_nonlocal_reference_stmt (gimple_stmt_iterator *, bool *,
+ struct walk_stmt_info *);
+
+/* Helper for convert_nonlocal_references, rewrite all references to VAR
+ and PARM_DECLs that belong to outer functions. */
+
+static bool
+convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+ struct nesting_info *const info = (struct nesting_info *) wi->info;
+ bool need_chain = 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)
+ {
+ bitmap_set_bit (new_suppress, DECL_UID (decl));
+ OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+ need_chain = 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_nonlocal_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_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info,
+ OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_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_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info,
+ OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ break;
+
+ default:
+ break;
+ }
+
+ return need_chain;
+}
+
+
+/* Callback for walk_gimple_stmt. Rewrite all references to VAR and
+ PARM_DECLs that belong to outer functions. This handles statements
+ that are not handled via the standard recursion done in
+ walk_gimple_stmt. STMT is the statement to examine, DATA is as in
+ convert_nonlocal_reference_op. Set *HANDLED_OPS_P to true if all the
+ operands of STMT have been handled by this function. */
+
+static tree
+convert_nonlocal_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_GOTO:
+ /* Don't walk non-local gotos for now. */
+ if (TREE_CODE (gimple_goto_dest (stmt)) != LABEL_DECL)
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ *handled_ops_p = true;
+ return NULL_TREE;
+ }
+ break;
+
+ 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 (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;
+
+ 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 (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+ DECL_CONTEXT (new_decl) = info->context;
+ DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+ 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;
+
+ 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