diff options
Diffstat (limited to 'gcc/cp/cp-gimplify.c')
| -rw-r--r-- | gcc/cp/cp-gimplify.c | 225 |
1 files changed, 194 insertions, 31 deletions
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index a9fb7bf..bd8f1a0 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -37,30 +37,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA enum bc_t { bc_break = 0, bc_continue = 1 }; -static struct cp_gimplify_ctx -{ - /* Stack of labels which are targets for "break" or "continue", - linked through TREE_CHAIN. */ - tree current_label[2]; -} *ctxp; - -static void -push_context (void) -{ - gcc_assert (!ctxp); - ctxp = ((struct cp_gimplify_ctx *) - xcalloc (1, sizeof (struct cp_gimplify_ctx))); -} - -static void -pop_context (void) -{ - gcc_assert (ctxp - && !ctxp->current_label[0] - && !ctxp->current_label[1]); - free (ctxp); - ctxp = NULL; -} +/* Stack of labels which are targets for "break" or "continue", + linked through TREE_CHAIN. */ +static tree bc_label[2]; /* Begin a scope which can be exited by a break or continue statement. BC indicates which. @@ -71,8 +50,8 @@ static tree begin_bc_block (enum bc_t bc) { tree label = create_artificial_label (); - TREE_CHAIN (label) = ctxp->current_label[bc]; - ctxp->current_label[bc] = label; + TREE_CHAIN (label) = bc_label[bc]; + bc_label[bc] = label; return label; } @@ -86,7 +65,7 @@ begin_bc_block (enum bc_t bc) static tree finish_bc_block (enum bc_t bc, tree label, tree body) { - gcc_assert (label == ctxp->current_label[bc]); + gcc_assert (label == bc_label[bc]); if (TREE_USED (label)) { @@ -99,7 +78,7 @@ finish_bc_block (enum bc_t bc, tree label, tree body) body = sl; } - ctxp->current_label[bc] = TREE_CHAIN (label); + bc_label[bc] = TREE_CHAIN (label); TREE_CHAIN (label) = NULL_TREE; return body; } @@ -110,7 +89,7 @@ finish_bc_block (enum bc_t bc, tree label, tree body) static tree build_bc_goto (enum bc_t bc) { - tree label = ctxp->current_label[bc]; + tree label = bc_label[bc]; if (label == NULL_TREE) { @@ -338,6 +317,36 @@ gimplify_switch_stmt (tree *stmt_p) *stmt_p = finish_bc_block (bc_break, break_block, *stmt_p); } +/* Hook into the middle of gimplifying an OMP_FOR node. This is required + in order to properly gimplify CONTINUE statements. Here we merely + manage the continue stack; the rest of the job is performed by the + regular gimplifier. */ + +static enum gimplify_status +cp_gimplify_omp_for (tree *expr_p) +{ + tree for_stmt = *expr_p; + tree cont_block; + + /* Protect ourselves from recursion. */ + if (OMP_FOR_GIMPLIFYING_P (for_stmt)) + return GS_UNHANDLED; + OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; + + /* Note that while technically the continue label is enabled too soon + here, we should have already diagnosed invalid continues nested within + statement expressions within the INIT, COND, or INCR expressions. */ + cont_block = begin_bc_block (bc_continue); + + gimplify_stmt (expr_p); + + OMP_FOR_BODY (for_stmt) + = finish_bc_block (bc_continue, cont_block, OMP_FOR_BODY (for_stmt)); + OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; + + return GS_ALL_DONE; +} + /* Gimplify an EXPR_STMT node. */ static void @@ -543,6 +552,10 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) ret = GS_ALL_DONE; break; + case OMP_FOR: + ret = cp_gimplify_omp_for (expr_p); + break; + case CONTINUE_STMT: *expr_p = build_bc_goto (bc_continue); ret = GS_ALL_DONE; @@ -686,7 +699,157 @@ cp_genericize (tree fndecl) pointer_set_destroy (p_set); /* Do everything else. */ - push_context (); c_genericize (fndecl); - pop_context (); + + gcc_assert (bc_label[bc_break] == NULL); + gcc_assert (bc_label[bc_continue] == NULL); +} + +/* Build code to apply FN to each member of ARG1 and ARG2. FN may be + NULL if there is in fact nothing to do. ARG2 may be null if FN + actually only takes one argument. */ + +static tree +cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) +{ + if (fn == NULL) + return NULL; + + if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) + { + tree inner_type = TREE_TYPE (arg1); + tree start1, end1, p1; + tree start2 = NULL, p2 = NULL; + tree ret = NULL, lab, t; + + start1 = arg1; + start2 = arg2; + do + { + inner_type = TREE_TYPE (inner_type); + start1 = build4 (ARRAY_REF, inner_type, start1, + size_zero_node, NULL, NULL); + if (arg2) + start2 = build4 (ARRAY_REF, inner_type, start2, + size_zero_node, NULL, NULL); + } + while (TREE_CODE (inner_type) == ARRAY_TYPE); + start1 = build_fold_addr_expr (start1); + if (arg2) + start2 = build_fold_addr_expr (start2); + + end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); + end1 = fold_convert (TREE_TYPE (start1), end1); + end1 = build2 (PLUS_EXPR, TREE_TYPE (start1), start1, end1); + + p1 = create_tmp_var (TREE_TYPE (start1), NULL); + t = build2 (MODIFY_EXPR, void_type_node, p1, start1); + append_to_statement_list (t, &ret); + + if (arg2) + { + p2 = create_tmp_var (TREE_TYPE (start2), NULL); + t = build2 (MODIFY_EXPR, void_type_node, p2, start2); + append_to_statement_list (t, &ret); + } + + lab = create_artificial_label (); + t = build1 (LABEL_EXPR, void_type_node, lab); + append_to_statement_list (t, &ret); + + t = NULL; + if (arg2) + t = tree_cons (NULL, p2, t); + t = tree_cons (NULL, p1, t); + t = build_call (fn, t); + append_to_statement_list (t, &ret); + + t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type)); + t = build2 (PLUS_EXPR, TREE_TYPE (p1), p1, t); + t = build2 (MODIFY_EXPR, void_type_node, p1, t); + append_to_statement_list (t, &ret); + + if (arg2) + { + t = fold_convert (TREE_TYPE (p2), TYPE_SIZE_UNIT (inner_type)); + t = build2 (PLUS_EXPR, TREE_TYPE (p2), p2, t); + t = build2 (MODIFY_EXPR, void_type_node, p2, t); + append_to_statement_list (t, &ret); + } + + t = build2 (NE_EXPR, boolean_type_node, p1, end1); + t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); + append_to_statement_list (t, &ret); + + return ret; + } + else + { + tree t = NULL; + if (arg2) + t = tree_cons (NULL, build_fold_addr_expr (arg2), t); + t = tree_cons (NULL, build_fold_addr_expr (arg1), t); + return build_call (fn, t); + } +} + +/* Return code to initialize DECL with its default constructor, or + NULL if there's nothing to do. */ + +tree +cxx_omp_clause_default_ctor (tree clause, tree decl) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), decl, NULL); + + return ret; +} + +/* Return code to initialize DST with a copy constructor from SRC. */ + +tree +cxx_omp_clause_copy_ctor (tree clause, tree dst, tree src) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), dst, src); + if (ret == NULL) + ret = build2 (MODIFY_EXPR, void_type_node, dst, src); + + return ret; +} + +/* Similarly, except use an assignment operator instead. */ + +tree +cxx_omp_clause_assign_op (tree clause, tree dst, tree src) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 2), dst, src); + if (ret == NULL) + ret = build2 (MODIFY_EXPR, void_type_node, dst, src); + + return ret; +} + +/* Return code to destroy DECL. */ + +tree +cxx_omp_clause_dtor (tree clause, tree decl) +{ + tree info = CP_OMP_CLAUSE_INFO (clause); + tree ret = NULL; + + if (info) + ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 1), decl, NULL); + + return ret; } |
