X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-nested.c;h=8f9fec58cf6bcf9261e30a6038ef1f956c87815c;hb=ec1936763426eda04e532df52fae10b7e3d01902;hp=a20e320ad2e1df7b493d0ce4a60c0e8369f964c9;hpb=a5268989afcfe7c737d3f7b6b81d6f2e1bf054a5;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index a20e320ad2e..8f9fec58cf6 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1,4 +1,4 @@ -/* Nested function decomposition for trees. +/* Nested function decomposition for GIMPLE. Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GCC. @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see -. */ + . */ #include "config.h" #include "system.h" @@ -27,7 +27,7 @@ #include "function.h" #include "tree-dump.h" #include "tree-inline.h" -#include "tree-gimple.h" +#include "gimple.h" #include "tree-iterator.h" #include "tree-flow.h" #include "cgraph.h" @@ -156,7 +156,7 @@ build_addr (tree exp, tree context) /* Building the ADDR_EXPR will compute a set of properties for that ADDR_EXPR. Those properties are unfortunately context - specific. ie, they are dependent on CURRENT_FUNCTION_DECL. + specific, i.e., they are dependent on CURRENT_FUNCTION_DECL. Temporarily set CURRENT_FUNCTION_DECL to the desired context, build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL. That @@ -183,6 +183,10 @@ insert_field_into_struct (tree type, tree field) TREE_CHAIN (field) = *p; *p = field; + + /* Set correct alignment for frame struct type. */ + if (TYPE_ALIGN (type) < DECL_ALIGN (field)) + TYPE_ALIGN (type) = DECL_ALIGN (field); } /* Build or return the RECORD_TYPE that describes the frame state that is @@ -254,7 +258,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, if (insert == NO_INSERT) { slot = pointer_map_contains (info->field_map, decl); - return slot ? *slot : NULL; + return slot ? (tree) *slot : NULL_TREE; } slot = pointer_map_insert (info->field_map, decl); @@ -287,7 +291,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, info->any_parm_remapped = true; } - return *slot; + return (tree) *slot; } /* Build or return the variable that holds the static chain within @@ -351,46 +355,69 @@ get_chain_field (struct nesting_info *info) return field; } +/* Initialize a new temporary with the GIMPLE_CALL STMT. */ + +static tree +init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi, + gimple call) +{ + tree t; + + t = create_tmp_var_for (info, gimple_call_return_type (call), NULL); + gimple_call_set_lhs (call, t); + if (! gsi_end_p (*gsi)) + gimple_set_location (call, gimple_location (gsi_stmt (*gsi))); + gsi_insert_before (gsi, call, GSI_SAME_STMT); + + return t; +} + + /* Copy EXP into a temporary. Allocate the temporary in the context of - INFO and insert the initialization statement before TSI. */ + INFO and insert the initialization statement before GSI. */ static tree -init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) +init_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi) { - tree t, stmt; + tree t; + gimple stmt; t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); - stmt = build_gimple_modify_stmt (t, exp); - SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); - tsi_link_before (tsi, stmt, TSI_SAME_STMT); + stmt = gimple_build_assign (t, exp); + if (! gsi_end_p (*gsi)) + gimple_set_location (stmt, gimple_location (gsi_stmt (*gsi))); + gsi_insert_before_without_update (gsi, stmt, GSI_SAME_STMT); return t; } + /* Similarly, but only do so to force EXP to satisfy is_gimple_val. */ static tree -tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) +gsi_gimplify_val (struct nesting_info *info, tree exp, + gimple_stmt_iterator *gsi) { if (is_gimple_val (exp)) return exp; else - return init_tmp_var (info, exp, tsi); + return init_tmp_var (info, exp, gsi); } /* Similarly, but copy from the temporary and insert the statement after the iterator. */ static tree -save_tmp_var (struct nesting_info *info, tree exp, - tree_stmt_iterator *tsi) +save_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi) { - tree t, stmt; + tree t; + gimple stmt; t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); - stmt = build_gimple_modify_stmt (exp, t); - SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); - tsi_link_after (tsi, stmt, TSI_SAME_STMT); + stmt = gimple_build_assign (exp, t); + if (! gsi_end_p (*gsi)) + gimple_set_location (stmt, gimple_location (gsi_stmt (*gsi))); + gsi_insert_after_without_update (gsi, stmt, GSI_SAME_STMT); return t; } @@ -429,6 +456,7 @@ get_trampoline_type (void) TYPE_NAME (trampoline_type) = get_identifier ("__builtin_trampoline"); TYPE_FIELDS (trampoline_type) = t; layout_type (trampoline_type); + DECL_CONTEXT (t) = trampoline_type; return trampoline_type; } @@ -445,7 +473,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl, if (insert == NO_INSERT) { slot = pointer_map_contains (info->var_map, decl); - return slot ? *slot : NULL; + return slot ? (tree) *slot : NULL_TREE; } slot = pointer_map_insert (info->var_map, decl); @@ -462,7 +490,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl, info->any_tramp_created = true; } - return *slot; + return (tree) *slot; } /* Build or return the field within the non-local frame state that holds @@ -507,232 +535,102 @@ get_nl_goto_field (struct nesting_info *info) return field; } - -/* Helper function for walk_stmts. Walk output operands of an ASM_EXPR. */ - -static void -walk_asm_expr (struct walk_stmt_info *wi, tree stmt) -{ - int noutputs = list_length (ASM_OUTPUTS (stmt)); - const char **oconstraints - = (const char **) alloca ((noutputs) * sizeof (const char *)); - int i; - tree link; - const char *constraint; - bool allows_mem, allows_reg, is_inout; - - wi->is_lhs = true; - for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link)) - { - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - oconstraints[i] = constraint; - parse_output_constraint (&constraint, i, 0, 0, &allows_mem, - &allows_reg, &is_inout); - - wi->val_only = (allows_reg || !allows_mem); - walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL); - } - - for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link)) - { - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - parse_input_constraint (&constraint, 0, 0, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); - - wi->val_only = (allows_reg || !allows_mem); - /* Although input "m" is not really a LHS, we need a lvalue. */ - wi->is_lhs = !wi->val_only; - walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL); - } - - wi->is_lhs = false; - wi->val_only = true; -} - -/* Iterate over all sub-statements of *TP calling walk_tree with - WI->CALLBACK for every sub-expression in each statement found. */ - -void -walk_stmts (struct walk_stmt_info *wi, tree *tp) -{ - tree t = *tp; - int walk_subtrees; - if (!t) - return; - - if (wi->want_locations && EXPR_HAS_LOCATION (t)) - input_location = EXPR_LOCATION (t); - - switch (TREE_CODE (t)) - { - case STATEMENT_LIST: - { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - wi->tsi = i; - walk_stmts (wi, tsi_stmt_ptr (i)); - } - } - break; - - case COND_EXPR: - walk_tree (&COND_EXPR_COND (t), wi->callback, wi, NULL); - walk_stmts (wi, &COND_EXPR_THEN (t)); - walk_stmts (wi, &COND_EXPR_ELSE (t)); - break; - case CATCH_EXPR: - walk_stmts (wi, &CATCH_BODY (t)); - break; - case EH_FILTER_EXPR: - walk_stmts (wi, &EH_FILTER_FAILURE (t)); - break; - case TRY_CATCH_EXPR: - case TRY_FINALLY_EXPR: - walk_stmts (wi, &TREE_OPERAND (t, 0)); - walk_stmts (wi, &TREE_OPERAND (t, 1)); - break; - - case BIND_EXPR: - if (wi->want_bind_expr) - { - walk_subtrees = 1; - wi->callback (tp, &walk_subtrees, wi); - if (!walk_subtrees) - break; - } - walk_stmts (wi, &BIND_EXPR_BODY (t)); - break; - - case RETURN_EXPR: - if (wi->want_return_expr) - { - walk_subtrees = 1; - wi->callback (tp, &walk_subtrees, wi); - if (!walk_subtrees) - break; - } - walk_stmts (wi, &TREE_OPERAND (t, 0)); - break; - - case GIMPLE_MODIFY_STMT: - /* A formal temporary lhs may use a COMPONENT_REF rhs. */ - wi->val_only = !is_gimple_formal_tmp_var (GIMPLE_STMT_OPERAND (t, 0)); - walk_tree (&GIMPLE_STMT_OPERAND (t, 1), wi->callback, wi, NULL); - - /* If the rhs is appropriate for a memory, we may use a - COMPONENT_REF on the lhs. */ - wi->val_only = !is_gimple_mem_rhs (GIMPLE_STMT_OPERAND (t, 1)); - wi->is_lhs = true; - walk_tree (&GIMPLE_STMT_OPERAND (t, 0), wi->callback, wi, NULL); - - wi->val_only = true; - wi->is_lhs = false; - break; - - case ASM_EXPR: - walk_asm_expr (wi, *tp); - break; - - default: - wi->val_only = true; - walk_tree (tp, wi->callback, wi, NULL); - break; - } -} - -/* Invoke CALLBACK on all statements of *STMT_P. */ +/* Invoke CALLBACK on all statements of GIMPLE sequence SEQ. */ static void -walk_body (walk_tree_fn callback, struct nesting_info *info, tree *stmt_p) +walk_body (walk_stmt_fn callback_stmt, walk_tree_fn callback_op, + struct nesting_info *info, gimple_seq seq) { struct walk_stmt_info wi; memset (&wi, 0, sizeof (wi)); - wi.callback = callback; wi.info = info; wi.val_only = true; - - walk_stmts (&wi, stmt_p); + walk_gimple_seq (seq, callback_stmt, callback_op, &wi); } -/* Invoke CALLBACK on all statements of INFO->CONTEXT. */ + +/* Invoke CALLBACK_STMT/CALLBACK_OP on all statements of INFO->CONTEXT. */ static inline void -walk_function (walk_tree_fn callback, struct nesting_info *info) +walk_function (walk_stmt_fn callback_stmt, walk_tree_fn callback_op, + struct nesting_info *info) { - walk_body (callback, info, &DECL_SAVED_TREE (info->context)); + walk_body (callback_stmt, callback_op, info, gimple_body (info->context)); } -/* Invoke CALLBACK on OMP_FOR init, cond, incr and pre-body. */ +/* Invoke CALLBACK on a GIMPLE_OMP_FOR's init, cond, incr and pre-body. */ static void -walk_omp_for (walk_tree_fn callback, struct nesting_info *info, tree for_stmt) +walk_gimple_omp_for (gimple for_stmt, + walk_stmt_fn callback_stmt, walk_tree_fn callback_op, + struct nesting_info *info) { struct walk_stmt_info wi; - tree t, list = NULL, empty; + gimple_seq seq; + tree t; + size_t i; - walk_body (callback, info, &OMP_FOR_PRE_BODY (for_stmt)); + walk_body (callback_stmt, callback_op, info, gimple_omp_for_pre_body (for_stmt)); - empty = build_empty_stmt (); - append_to_statement_list_force (empty, &list); + seq = gimple_seq_alloc (); memset (&wi, 0, sizeof (wi)); - wi.callback = callback; wi.info = info; - wi.tsi = tsi_last (list); + wi.gsi = gsi_last (seq); - t = OMP_FOR_INIT (for_stmt); - gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); - SET_EXPR_LOCUS (empty, EXPR_LOCUS (t)); - wi.val_only = false; - walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL); - wi.val_only = true; - wi.is_lhs = false; - walk_tree (&GIMPLE_STMT_OPERAND (t, 1), callback, &wi, NULL); - - t = OMP_FOR_COND (for_stmt); - gcc_assert (COMPARISON_CLASS_P (t)); - SET_EXPR_LOCUS (empty, EXPR_LOCUS (t)); - wi.val_only = false; - walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL); - wi.val_only = true; - wi.is_lhs = false; - walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL); - - t = OMP_FOR_INCR (for_stmt); - gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT); - SET_EXPR_LOCUS (empty, EXPR_LOCUS (t)); - wi.val_only = false; - walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL); - t = GIMPLE_STMT_OPERAND (t, 1); - gcc_assert (BINARY_CLASS_P (t)); - wi.val_only = false; - walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL); - wi.val_only = true; - wi.is_lhs = false; - walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL); + for (i = 0; i < gimple_omp_for_collapse (for_stmt); i++) + { + wi.val_only = false; + walk_tree (gimple_omp_for_index_ptr (for_stmt, i), callback_op, + &wi, NULL); + wi.val_only = true; + wi.is_lhs = false; + walk_tree (gimple_omp_for_initial_ptr (for_stmt, i), callback_op, + &wi, NULL); + + wi.val_only = true; + wi.is_lhs = false; + walk_tree (gimple_omp_for_final_ptr (for_stmt, i), callback_op, + &wi, NULL); + + t = gimple_omp_for_incr (for_stmt, i); + gcc_assert (BINARY_CLASS_P (t)); + wi.val_only = false; + walk_tree (&TREE_OPERAND (t, 0), callback_op, &wi, NULL); + wi.val_only = true; + wi.is_lhs = false; + walk_tree (&TREE_OPERAND (t, 1), callback_op, &wi, NULL); + } - /* Remove empty statement added above from the end of statement list. */ - tsi_delink (&wi.tsi); - append_to_statement_list (list, &OMP_FOR_PRE_BODY (for_stmt)); + if (gimple_seq_empty_p (seq)) + gimple_seq_free (seq); + else + { + gimple_seq pre_body = gimple_omp_for_pre_body (for_stmt); + annotate_all_with_location (seq, gimple_location (for_stmt)); + gimple_seq_add_seq (&pre_body, seq); + gimple_omp_for_set_pre_body (for_stmt, pre_body); + } } /* Similarly for ROOT and all functions nested underneath, depth first. */ static void -walk_all_functions (walk_tree_fn callback, struct nesting_info *root) +walk_all_functions (walk_stmt_fn callback_stmt, walk_tree_fn callback_op, + struct nesting_info *root) { do { if (root->inner) - walk_all_functions (callback, root->inner); - walk_function (callback, root); + walk_all_functions (callback_stmt, callback_op, root->inner); + walk_function (callback_stmt, callback_op, root); root = root->next; } while (root); } - + + /* We have to check for a fairly pathological case. The operands of function nested function are to be interpreted in the context of the enclosing function. So if any are variably-sized, they will get remapped when the @@ -765,7 +663,7 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl) for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) { for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg)) - if (variably_modified_type_p (TREE_TYPE (arg), 0), orig_fndecl) + if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl)) return true; if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl)) @@ -808,7 +706,7 @@ create_nesting_tree (struct cgraph_node *cgn) static tree get_static_chain (struct nesting_info *info, tree target_context, - tree_stmt_iterator *tsi) + gimple_stmt_iterator *gsi) { struct nesting_info *i; tree x; @@ -827,20 +725,21 @@ get_static_chain (struct nesting_info *info, tree target_context, x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); - x = init_tmp_var (info, x, tsi); + x = init_tmp_var (info, x, gsi); } } return x; } + /* Return an expression referencing FIELD from TARGET_CONTEXT's non-local frame as seen from INFO->CONTEXT. Insert any necessary computations - before TSI. */ + before GSI. */ static tree get_frame_field (struct nesting_info *info, tree target_context, - tree field, tree_stmt_iterator *tsi) + tree field, gimple_stmt_iterator *gsi) { struct nesting_info *i; tree x; @@ -861,7 +760,7 @@ get_frame_field (struct nesting_info *info, tree target_context, x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); - x = init_tmp_var (info, x, tsi); + x = init_tmp_var (info, x, gsi); } x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); @@ -871,7 +770,8 @@ get_frame_field (struct nesting_info *info, tree target_context, return x; } -/* A subroutine of convert_nonlocal_reference. Create a local variable + +/* A subroutine of convert_nonlocal_reference_op. Create a local variable in the nested function with DECL_VALUE_EXPR set to reference the true variable in the parent function. This is used both for debug info and in OpenMP lowering. */ @@ -887,7 +787,7 @@ get_nonlocal_debug_decl (struct nesting_info *info, tree decl) slot = pointer_map_insert (info->var_map, decl); if (*slot) - return *slot; + return (tree) *slot; target_context = decl_function_context (decl); @@ -938,7 +838,8 @@ get_nonlocal_debug_decl (struct nesting_info *info, tree decl) return new_decl; } -/* Called via walk_function+walk_tree, rewrite all references to VAR + +/* Callback for walk_gimple_stmt, rewrite all references to VAR and PARM_DECLs that belong to outer functions. The rewrite will involve some number of structure accesses back up @@ -946,16 +847,12 @@ get_nonlocal_debug_decl (struct nesting_info *info, tree decl) be CHAIN->FOO. For two levels it'll be CHAIN->__chain->FOO. Further indirections apply to decls for which use_pointer_in_frame is true. */ -static bool convert_nonlocal_omp_clauses (tree *, struct walk_stmt_info *); - static tree -convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) +convert_nonlocal_reference_op (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info; + struct nesting_info *const info = (struct nesting_info *) wi->info; tree t = *tp; - tree save_local_var_chain; - bitmap save_suppress; *walk_subtrees = 0; switch (TREE_CODE (t)) @@ -980,10 +877,10 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) for (i = info->outer; i->context != target_context; i = i->outer) continue; x = lookup_field_for_decl (i, t, INSERT); - x = get_frame_field (info, target_context, x, &wi->tsi); + x = get_frame_field (info, target_context, x, &wi->gsi); if (use_pointer_in_frame (t)) { - x = init_tmp_var (info, x, &wi->tsi); + x = init_tmp_var (info, x, &wi->gsi); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); } } @@ -991,25 +888,15 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) if (wi->val_only) { if (wi->is_lhs) - x = save_tmp_var (info, x, &wi->tsi); + x = save_tmp_var (info, x, &wi->gsi); else - x = init_tmp_var (info, x, &wi->tsi); + x = init_tmp_var (info, x, &wi->gsi); } *tp = x; } break; - case GOTO_EXPR: - /* Don't walk non-local gotos for now. */ - if (TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL) - { - *walk_subtrees = 1; - wi->val_only = true; - wi->is_lhs = false; - } - break; - case LABEL_DECL: /* We're taking the address of a label from a parent function, but this is not itself a non-local goto. Mark the label such that it @@ -1026,15 +913,15 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) wi->val_only = false; wi->is_lhs = false; wi->changed = false; - walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference_op, wi, 0); wi->val_only = true; if (wi->changed) { tree save_context; - /* If we changed anything, then TREE_INVARIANT is be wrong, - since we're no longer directly referencing a decl. */ + /* If we changed anything, we might no longer be directly + referencing a decl. */ save_context = current_function_decl; current_function_decl = info->context; recompute_tree_invariant_for_addr_expr (t); @@ -1044,7 +931,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) where we only accept variables (and min_invariant, presumably), then compute the address into a temporary. */ if (save_val_only) - *tp = tsi_gimplify_val (wi->info, t, &wi->tsi); + *tp = gsi_gimplify_val ((struct nesting_info *) wi->info, + t, &wi->gsi); } } break; @@ -1063,28 +951,28 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) 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_nonlocal_reference, wi, + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op, wi, NULL); else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) { - walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, - NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, - NULL); - walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi, - NULL); + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op, + wi, NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op, + wi, NULL); + walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference_op, + wi, NULL); } else if (TREE_CODE (t) == BIT_FIELD_REF) { - walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, - NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, - NULL); + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op, + wi, NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op, + wi, NULL); } } wi->val_only = false; - walk_tree (tp, convert_nonlocal_reference, wi, NULL); + walk_tree (tp, convert_nonlocal_reference_op, wi, NULL); break; case VIEW_CONVERT_EXPR: @@ -1094,51 +982,6 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 1; break; - case OMP_PARALLEL: - save_suppress = info->suppress_expansion; - if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), 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) = OMP_PARALLEL_CLAUSES (t); - OMP_PARALLEL_CLAUSES (t) = c; - } - - save_local_var_chain = info->new_local_var_chain; - info->new_local_var_chain = NULL; - - walk_body (convert_nonlocal_reference, info, &OMP_PARALLEL_BODY (t)); - - if (info->new_local_var_chain) - declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false); - info->new_local_var_chain = save_local_var_chain; - info->suppress_expansion = save_suppress; - break; - - case OMP_FOR: - save_suppress = info->suppress_expansion; - convert_nonlocal_omp_clauses (&OMP_FOR_CLAUSES (t), wi); - walk_omp_for (convert_nonlocal_reference, info, t); - walk_body (convert_nonlocal_reference, info, &OMP_FOR_BODY (t)); - info->suppress_expansion = save_suppress; - break; - - case OMP_SECTIONS: - case OMP_SINGLE: - save_suppress = info->suppress_expansion; - convert_nonlocal_omp_clauses (&OMP_CLAUSES (t), wi); - walk_body (convert_nonlocal_reference, info, &OMP_BODY (t)); - info->suppress_expansion = save_suppress; - break; - - case OMP_SECTION: - case OMP_MASTER: - case OMP_ORDERED: - walk_body (convert_nonlocal_reference, info, &OMP_BODY (t)); - break; - default: if (!IS_TYPE_OR_DECL_P (t)) { @@ -1152,11 +995,17 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } +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 *info = wi->info; - bool need_chain = false; + 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; @@ -1168,13 +1017,25 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) { 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_LASTPRIVATE: - case OMP_CLAUSE_REDUCTION: 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)); @@ -1191,14 +1052,16 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_NUM_THREADS: wi->val_only = true; wi->is_lhs = false; - convert_nonlocal_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy, - wi); + 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: @@ -1208,9 +1071,145 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) 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 @@ -1224,7 +1223,7 @@ get_local_debug_decl (struct nesting_info *info, tree decl, tree field) slot = pointer_map_insert (info->var_map, decl); if (*slot) - return *slot; + return (tree) *slot; /* Make sure frame_decl gets created. */ (void) get_frame_type (info); @@ -1255,21 +1254,20 @@ get_local_debug_decl (struct nesting_info *info, tree decl, tree field) return new_decl; } -/* Called via walk_function+walk_tree, rewrite all references to VAR + +/* 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 (tree *tp, int *walk_subtrees, void *data) +convert_local_reference_op (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info; + struct nesting_info *const info = (struct nesting_info *) wi->info; tree t = *tp, field, x; bool save_val_only; - tree save_local_var_chain; - bitmap save_suppress; *walk_subtrees = 0; switch (TREE_CODE (t)) @@ -1297,14 +1295,14 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) 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->tsi); + 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->tsi); + x = save_tmp_var (info, x, &wi->gsi); else - x = init_tmp_var (info, x, &wi->tsi); + x = init_tmp_var (info, x, &wi->gsi); } *tp = x; @@ -1316,7 +1314,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) wi->val_only = false; wi->is_lhs = false; wi->changed = false; - walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + walk_tree (&TREE_OPERAND (t, 0), convert_local_reference_op, wi, NULL); wi->val_only = save_val_only; /* If we converted anything ... */ @@ -1335,7 +1333,8 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) /* If we are in a context where we only accept values, then compute the address into a temporary. */ if (save_val_only) - *tp = tsi_gimplify_val (wi->info, t, &wi->tsi); + *tp = gsi_gimplify_val ((struct nesting_info *) wi->info, + t, &wi->gsi); } break; @@ -1354,28 +1353,28 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) 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, wi, + 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, wi, + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi, NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi, NULL); - walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi, + 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, wi, + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi, NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi, NULL); } } wi->val_only = false; - walk_tree (tp, convert_local_reference, wi, NULL); + walk_tree (tp, convert_local_reference_op, wi, NULL); wi->val_only = save_val_only; break; @@ -1386,51 +1385,6 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 1; break; - case OMP_PARALLEL: - save_suppress = info->suppress_expansion; - if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi)) - { - tree c; - (void) get_frame_type (info); - c = build_omp_clause (OMP_CLAUSE_SHARED); - OMP_CLAUSE_DECL (c) = info->frame_decl; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t); - OMP_PARALLEL_CLAUSES (t) = c; - } - - save_local_var_chain = info->new_local_var_chain; - info->new_local_var_chain = NULL; - - walk_body (convert_local_reference, info, &OMP_PARALLEL_BODY (t)); - - if (info->new_local_var_chain) - declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false); - info->new_local_var_chain = save_local_var_chain; - info->suppress_expansion = save_suppress; - break; - - case OMP_FOR: - save_suppress = info->suppress_expansion; - convert_local_omp_clauses (&OMP_FOR_CLAUSES (t), wi); - walk_omp_for (convert_local_reference, info, t); - walk_body (convert_local_reference, info, &OMP_FOR_BODY (t)); - info->suppress_expansion = save_suppress; - break; - - case OMP_SECTIONS: - case OMP_SINGLE: - save_suppress = info->suppress_expansion; - convert_local_omp_clauses (&OMP_CLAUSES (t), wi); - walk_body (convert_local_reference, info, &OMP_BODY (t)); - info->suppress_expansion = save_suppress; - break; - - case OMP_SECTION: - case OMP_MASTER: - case OMP_ORDERED: - walk_body (convert_local_reference, info, &OMP_BODY (t)); - break; - default: if (!IS_TYPE_OR_DECL_P (t)) { @@ -1444,11 +1398,17 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) 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 *info = wi->info; - bool need_frame = false; + 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; @@ -1460,13 +1420,25 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) { 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_LASTPRIVATE: - case OMP_CLAUSE_REDUCTION: 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)) { @@ -1489,13 +1461,16 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_NUM_THREADS: wi->val_only = true; wi->is_lhs = false; - convert_local_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy, wi); + 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: @@ -1505,30 +1480,163 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) 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_tree, rewrite all GOTO_EXPRs that - reference labels from outer functions. The rewrite will be a + +/* 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 (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; + + 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 (tree *tp, int *walk_subtrees, void *data) +convert_nl_goto_reference (gimple_stmt_iterator *gsi, bool *handled_ops_p, + struct walk_stmt_info *wi) { - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info, *i; - tree t = *tp, label, new_label, target_context, x, field; + 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); - *walk_subtrees = 0; - if (TREE_CODE (t) != GOTO_EXPR) - return NULL_TREE; - label = GOTO_DESTINATION (t); + if (gimple_code (stmt) != GIMPLE_GOTO) + { + *handled_ops_p = false; + return NULL_TREE; + } + + label = gimple_goto_dest (stmt); if (TREE_CODE (label) != LABEL_DECL) - return NULL_TREE; + { + *handled_ops_p = false; + return NULL_TREE; + } + target_context = decl_function_context (label); if (target_context == info->context) - return NULL_TREE; + { + *handled_ops_p = false; + return NULL_TREE; + } for (i = info->outer; target_context != i->context; i = i->outer) continue; @@ -1548,73 +1656,84 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) *slot = new_label; } else - new_label = *slot; + new_label = (tree) *slot; /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */ field = get_nl_goto_field (i); - x = get_frame_field (info, target_context, field, &wi->tsi); + x = get_frame_field (info, target_context, field, &wi->gsi); x = build_addr (x, target_context); - x = tsi_gimplify_val (info, x, &wi->tsi); - x = build_call_expr (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2, - build_addr (new_label, target_context), x); - - SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi))); - *tsi_stmt_ptr (wi->tsi) = x; + x = gsi_gimplify_val (info, x, &wi->gsi); + call = gimple_build_call (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2, + build_addr (new_label, target_context), x); + gsi_replace (&wi->gsi, call, false); + /* We have handled all of STMT's operands, no need to keep going. */ + *handled_ops_p = true; return NULL_TREE; } -/* Called via walk_function+walk_tree, rewrite all LABEL_EXPRs that + +/* Called via walk_function+walk_tree, rewrite all GIMPLE_LABELs whose labels are referenced via nonlocal goto from a nested function. The rewrite will involve installing a newly generated DECL_NONLOCAL label, and - (potentially) a branch around the rtl gunk that is assumed to be + (potentially) a branch around the rtl gunk that is assumed to be attached to such a label. */ static tree -convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data) +convert_nl_goto_receiver (gimple_stmt_iterator *gsi, bool *handled_ops_p, + struct walk_stmt_info *wi) { - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info; - tree t = *tp, label, new_label, x; - tree_stmt_iterator tmp_tsi; + struct nesting_info *const info = (struct nesting_info *) wi->info; + tree label, new_label; + gimple_stmt_iterator tmp_gsi; void **slot; + gimple stmt = gsi_stmt (*gsi); - *walk_subtrees = 0; - if (TREE_CODE (t) != LABEL_EXPR) - return NULL_TREE; - label = LABEL_EXPR_LABEL (t); + if (gimple_code (stmt) != GIMPLE_LABEL) + { + *handled_ops_p = false; + return NULL_TREE; + } + + label = gimple_label_label (stmt); slot = pointer_map_contains (info->var_map, label); if (!slot) - return NULL_TREE; + { + *handled_ops_p = false; + return NULL_TREE; + } /* If there's any possibility that the previous statement falls through, then we must branch around the new non-local label. */ - tmp_tsi = wi->tsi; - tsi_prev (&tmp_tsi); - if (tsi_end_p (tmp_tsi) || block_may_fallthru (tsi_stmt (tmp_tsi))) + tmp_gsi = wi->gsi; + gsi_prev (&tmp_gsi); + if (gsi_end_p (tmp_gsi) || gimple_stmt_may_fallthru (gsi_stmt (tmp_gsi))) { - x = build1 (GOTO_EXPR, void_type_node, label); - tsi_link_before (&wi->tsi, x, TSI_SAME_STMT); + gimple stmt = gimple_build_goto (label); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); } new_label = (tree) *slot; - x = build1 (LABEL_EXPR, void_type_node, new_label); - tsi_link_before (&wi->tsi, x, TSI_SAME_STMT); + stmt = gimple_build_label (new_label); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + *handled_ops_p = true; return NULL_TREE; } -/* Called via walk_function+walk_tree, rewrite all references to addresses + +/* Called via walk_function+walk_stmt, rewrite all references to addresses of nested functions that require the use of trampolines. The rewrite will involve a reference a trampoline generated for the occasion. */ static tree -convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) +convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info, *i; - tree t = *tp, decl, target_context, x; + struct nesting_info *const info = (struct nesting_info *) wi->info, *i; + tree t = *tp, decl, target_context, x, builtin; + gimple call; *walk_subtrees = 0; switch (TREE_CODE (t)) @@ -1640,6 +1759,10 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) if (DECL_NO_STATIC_CHAIN (decl)) break; + /* If we don't want a trampoline, then don't build one. */ + if (TREE_NO_TRAMPOLINE (t)) + break; + /* Lookup the immediate parent of the callee, as that's where we need to insert the trampoline. */ for (i = info; i->context != target_context; i = i->outer) @@ -1647,84 +1770,103 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) x = lookup_tramp_for_decl (i, decl, INSERT); /* Compute the address of the field holding the trampoline. */ - x = get_frame_field (info, target_context, x, &wi->tsi); + x = get_frame_field (info, target_context, x, &wi->gsi); x = build_addr (x, target_context); - x = tsi_gimplify_val (info, x, &wi->tsi); + x = gsi_gimplify_val (info, x, &wi->gsi); /* Do machine-specific ugliness. Normally this will involve computing extra alignment, but it can really be anything. */ - x = build_call_expr (implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE], - 1, x); - x = init_tmp_var (info, x, &wi->tsi); + builtin = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE]; + call = gimple_build_call (builtin, 1, x); + x = init_tmp_var_with_call (info, &wi->gsi, call); /* Cast back to the proper function type. */ x = build1 (NOP_EXPR, TREE_TYPE (t), x); - x = init_tmp_var (info, x, &wi->tsi); + x = init_tmp_var (info, x, &wi->gsi); *tp = x; break; - case CALL_EXPR: - /* Only walk call arguments, lest we generate trampolines for - direct calls. */ + default: + if (!IS_TYPE_OR_DECL_P (t)) + *walk_subtrees = 1; + break; + } + + return NULL_TREE; +} + + +/* Called via walk_function+walk_gimple_stmt, rewrite all references + to addresses of nested functions that require the use of + trampolines. The rewrite will involve a reference a trampoline + generated for the occasion. */ + +static tree +convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, + struct walk_stmt_info *wi) +{ + gimple stmt = gsi_stmt (*gsi); + + switch (gimple_code (stmt)) + { + case GIMPLE_CALL: { - int nargs = call_expr_nargs (t); - int i; + /* Only walk call arguments, lest we generate trampolines for + direct calls. */ + unsigned long i, nargs = gimple_call_num_args (stmt); for (i = 0; i < nargs; i++) - walk_tree (&CALL_EXPR_ARG (t, i), convert_tramp_reference, wi, NULL); + walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op, + wi, NULL); + + *handled_ops_p = true; + return NULL_TREE; } - break; default: - if (!IS_TYPE_OR_DECL_P (t)) - *walk_subtrees = 1; break; } + *handled_ops_p = false; return NULL_TREE; } -/* Called via walk_function+walk_tree, rewrite all CALL_EXPRs that - reference nested functions to make sure that the static chain is - set up properly for the call. */ + + +/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_CALLs + that reference nested functions to make sure that the static chain + is set up properly for the call. */ static tree -convert_call_expr (tree *tp, int *walk_subtrees, void *data) +convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, + struct walk_stmt_info *wi) { - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct nesting_info *info = wi->info; - tree t = *tp, decl, target_context; + struct nesting_info *const info = (struct nesting_info *) wi->info; + tree decl, target_context; char save_static_chain_added; int i; + gimple stmt = gsi_stmt (*gsi); - *walk_subtrees = 0; - switch (TREE_CODE (t)) + switch (gimple_code (stmt)) { - case CALL_EXPR: - decl = get_callee_fndecl (t); + case GIMPLE_CALL: + decl = gimple_call_fndecl (stmt); if (!decl) break; target_context = decl_function_context (decl); if (target_context && !DECL_NO_STATIC_CHAIN (decl)) { - CALL_EXPR_STATIC_CHAIN (t) - = get_static_chain (info, target_context, &wi->tsi); - info->static_chain_added - |= (1 << (info->context != target_context)); + gimple_call_set_chain (stmt, get_static_chain (info, target_context, + &wi->gsi)); + info->static_chain_added |= (1 << (info->context != target_context)); } break; - case RETURN_EXPR: - case GIMPLE_MODIFY_STMT: - case WITH_SIZE_EXPR: - /* Only return modify and with_size_expr may contain calls. */ - *walk_subtrees = 1; - break; - - case OMP_PARALLEL: + case GIMPLE_OMP_PARALLEL: + case GIMPLE_OMP_TASK: save_static_chain_added = info->static_chain_added; info->static_chain_added = 0; - walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t)); + walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt)); for (i = 0; i < 2; i++) { tree c, decl; @@ -1732,7 +1874,9 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data) continue; decl = i ? get_chain_decl (info) : info->frame_decl; /* Don't add CHAIN.* or FRAME.* twice. */ - for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c)) + for (c = gimple_omp_taskreg_clauses (stmt); + c; + c = OMP_CLAUSE_CHAIN (c)) if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED) && OMP_CLAUSE_DECL (c) == decl) @@ -1742,32 +1886,37 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data) c = build_omp_clause (i ? OMP_CLAUSE_FIRSTPRIVATE : OMP_CLAUSE_SHARED); OMP_CLAUSE_DECL (c) = decl; - OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t); - OMP_PARALLEL_CLAUSES (t) = c; + OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt); + gimple_omp_taskreg_set_clauses (stmt, c); } } info->static_chain_added |= save_static_chain_added; break; - case OMP_FOR: - walk_body (convert_call_expr, info, &OMP_FOR_PRE_BODY (t)); + case GIMPLE_OMP_FOR: + walk_body (convert_gimple_call, NULL, info, + gimple_omp_for_pre_body (stmt)); /* FALLTHRU */ - case OMP_SECTIONS: - case OMP_SECTION: - case OMP_SINGLE: - case OMP_MASTER: - case OMP_ORDERED: - case OMP_CRITICAL: - walk_body (convert_call_expr, info, &OMP_BODY (t)); + case GIMPLE_OMP_SECTIONS: + case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_ORDERED: + case GIMPLE_OMP_CRITICAL: + walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt)); break; default: - break; + /* Keep looking for other operands. */ + *handled_ops_p = false; + return NULL_TREE; } + *handled_ops_p = true; return NULL_TREE; } + /* Walk the nesting tree starting with ROOT, depth first. Convert all trampolines and call expressions. On the way back up, determine if a nested function actually uses its static chain; if not, remember that. */ @@ -1780,8 +1929,9 @@ convert_all_function_calls (struct nesting_info *root) if (root->inner) convert_all_function_calls (root->inner); - walk_function (convert_tramp_reference, root); - walk_function (convert_call_expr, root); + walk_function (convert_tramp_reference_stmt, convert_tramp_reference_op, + root); + walk_function (convert_gimple_call, NULL, root); /* If the function does not use a static chain, then remember that. */ if (root->outer && !root->chain_decl && !root->chain_field) @@ -1802,10 +1952,13 @@ convert_all_function_calls (struct nesting_info *root) static void finalize_nesting_tree_1 (struct nesting_info *root) { - tree stmt_list = NULL; + gimple_seq stmt_list; + gimple stmt; tree context = root->context; struct function *sf; + stmt_list = NULL; + /* If we created a non-local frame type or decl, we need to lay them out at this time. */ if (root->frame_type) @@ -1840,8 +1993,17 @@ finalize_nesting_tree_1 (struct nesting_info *root) y = build3 (COMPONENT_REF, TREE_TYPE (field), root->frame_decl, field, NULL_TREE); - x = build_gimple_modify_stmt (y, x); - append_to_statement_list (x, &stmt_list); + stmt = gimple_build_assign (y, x); + gimple_seq_add_stmt (&stmt_list, stmt); + /* If the assignment is from a non-register the stmt is + not valid gimple. Make it so by using a temporary instead. */ + if (!is_gimple_reg (x) + && is_gimple_reg_type (TREE_TYPE (x))) + { + gimple_stmt_iterator gsi = gsi_last (stmt_list); + x = init_tmp_var (root, x, &gsi); + gimple_assign_set_rhs1 (stmt, x); + } } } @@ -1851,8 +2013,8 @@ finalize_nesting_tree_1 (struct nesting_info *root) { tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field), root->frame_decl, root->chain_field, NULL_TREE); - x = build_gimple_modify_stmt (x, get_chain_decl (root)); - append_to_statement_list (x, &stmt_list); + stmt = gimple_build_assign (x, get_chain_decl (root)); + gimple_seq_add_stmt (&stmt_list, stmt); } /* If trampolines were created, then we need to initialize them. */ @@ -1879,19 +2041,19 @@ finalize_nesting_tree_1 (struct nesting_info *root) arg1 = build_addr (x, context); x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE]; - x = build_call_expr (x, 3, arg1, arg2, arg3); - append_to_statement_list (x, &stmt_list); + stmt = gimple_build_call (x, 3, arg1, arg2, arg3); + gimple_seq_add_stmt (&stmt_list, stmt); } } /* If we created initialization statements, insert them. */ if (stmt_list) { - annotate_all_with_locus (&stmt_list, - DECL_SOURCE_LOCATION (context)); - append_to_statement_list (BIND_EXPR_BODY (DECL_SAVED_TREE (context)), - &stmt_list); - BIND_EXPR_BODY (DECL_SAVED_TREE (context)) = stmt_list; + gimple bind; + annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context)); + bind = gimple_seq_first_stmt (gimple_body (context)); + gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind)); + gimple_bind_set_body (bind, stmt_list); } /* If a chain_decl was created, then it needs to be registered with @@ -1911,10 +2073,12 @@ finalize_nesting_tree_1 (struct nesting_info *root) /* Make sure all new local variables get inserted into the proper BIND_EXPR. */ if (root->new_local_var_chain) - declare_vars (root->new_local_var_chain, DECL_SAVED_TREE (root->context), + declare_vars (root->new_local_var_chain, + gimple_seq_first_stmt (gimple_body (root->context)), false); if (root->debug_var_chain) - declare_vars (root->debug_var_chain, DECL_SAVED_TREE (root->context), + declare_vars (root->debug_var_chain, + gimple_seq_first_stmt (gimple_body (root->context)), true); /* Dump the translated tree function. */ @@ -1998,10 +2162,14 @@ lower_nested_functions (tree fndecl) bitmap_obstack_initialize (&nesting_info_bitmap_obstack); root = create_nesting_tree (cgn); - walk_all_functions (convert_nonlocal_reference, root); - walk_all_functions (convert_local_reference, root); - walk_all_functions (convert_nl_goto_reference, root); - walk_all_functions (convert_nl_goto_receiver, root); + walk_all_functions (convert_nonlocal_reference_stmt, + convert_nonlocal_reference_op, + root); + walk_all_functions (convert_local_reference_stmt, + convert_local_reference_op, + root); + walk_all_functions (convert_nl_goto_reference, NULL, root); + walk_all_functions (convert_nl_goto_receiver, NULL, root); convert_all_function_calls (root); finalize_nesting_tree (root); unnest_nesting_tree (root);