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; return label; }
static tree begin_bc_block (enum bc_t bc, location_t location) { tree label = create_artificial_label (location); DECL_CHAIN (label) = bc_label[bc]; bc_label[bc] = label; return label; }
static tree begin_bc_block (enum bc_t bc) { tree label = create_artificial_label (); DECL_NAME (label) = ctxp->bc_id[bc]; TREE_CHAIN (label) = ctxp->current_bc_label; ctxp->current_bc_label = label; return label; }
static void lower_builtin_posix_memalign (gimple_stmt_iterator *gsi) { gimple stmt, call = gsi_stmt (*gsi); tree pptr = gimple_call_arg (call, 0); tree align = gimple_call_arg (call, 1); tree res = gimple_call_lhs (call); tree ptr = create_tmp_reg (ptr_type_node, NULL); if (TREE_CODE (pptr) == ADDR_EXPR) { tree tem = create_tmp_var (ptr_type_node, NULL); TREE_ADDRESSABLE (tem) = 1; gimple_call_set_arg (call, 0, build_fold_addr_expr (tem)); stmt = gimple_build_assign (ptr, tem); } else stmt = gimple_build_assign (ptr, fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0))); if (res == NULL_TREE) { res = create_tmp_reg (integer_type_node, NULL); gimple_call_set_lhs (call, res); } tree align_label = create_artificial_label (UNKNOWN_LOCATION); tree noalign_label = create_artificial_label (UNKNOWN_LOCATION); gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node, align_label, noalign_label); gsi_insert_after (gsi, cond, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_ASSUME_ALIGNED), 2, ptr, align); gimple_call_set_lhs (stmt, ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_assign (fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0)), ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (noalign_label), GSI_NEW_STMT); }
static void lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) { gimple stmt = gsi_stmt (*gsi); gimple t; int i; return_statements_t tmp_rs; /* Match this up with an existing return statement that's been created. */ for (i = data->return_statements.length () - 1; i >= 0; i--) { tmp_rs = data->return_statements[i]; if (gimple_return_retval (stmt) == gimple_return_retval (tmp_rs.stmt)) { /* Remove the line number from the representative return statement. It now fills in for many such returns. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (tmp_rs.stmt, UNKNOWN_LOCATION); goto found; } } /* Not found. Create a new label and record the return statement. */ tmp_rs.label = create_artificial_label (cfun->function_end_locus); tmp_rs.stmt = stmt; data->return_statements.safe_push (tmp_rs); /* Generate a goto statement and remove the return statement. */ found: /* When not optimizing, make sure user returns are preserved. */ if (!optimize && gimple_has_location (stmt)) DECL_ARTIFICIAL (tmp_rs.label) = 0; t = gimple_build_goto (tmp_rs.label); gimple_set_location (t, gimple_location (stmt)); gimple_set_block (t, gimple_block (stmt)); gsi_insert_before (gsi, t, GSI_SAME_STMT); gsi_remove (gsi, false); }
static void lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) { tree stmt = tsi_stmt (*tsi); tree value, t, label; /* Extract the value being returned. */ value = TREE_OPERAND (stmt, 0); if (value && TREE_CODE (value) == MODIFY_EXPR) value = TREE_OPERAND (value, 1); /* Match this up with an existing return statement that's been created. */ for (t = data->return_statements; t ; t = TREE_CHAIN (t)) { tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0); if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR) tvalue = TREE_OPERAND (tvalue, 1); if (value == tvalue) { label = TREE_PURPOSE (t); goto found; } } /* Not found. Create a new label and record the return statement. */ label = create_artificial_label (); data->return_statements = tree_cons (label, stmt, data->return_statements); /* Generate a goto statement and remove the return statement. */ found: t = build (GOTO_EXPR, void_type_node, label); SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); tsi_link_before (tsi, t, TSI_SAME_STMT); tsi_delink (tsi); }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple g; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; dest = gimple_call_lhs (stmt); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; tree t; gimple x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ if (gimple_seq_may_fallthru (lowered_body) && (data.return_statements.is_empty () || gimple_return_retval (data.return_statements.last().stmt) != NULL)) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } /* If the function calls __builtin_setjmp, we need to emit the computed goto that will serve as the unique dispatcher for all the receivers. */ if (data.calls_builtin_setjmp) { tree disp_label, disp_var, arg; /* Build 'DISP_LABEL:' and insert. */ disp_label = create_artificial_label (cfun->function_end_locus); /* This mark will create forward edges from every call site. */ DECL_NONLOCAL (disp_label) = 1; cfun->has_nonlocal_label = 1; x = gimple_build_label (disp_label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' and insert. */ disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); arg = build_addr (disp_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER); x = gimple_build_call (t, 1, arg); gimple_call_set_lhs (x, disp_var); /* Build 'goto DISP_VAR;' and insert. */ gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); x = gimple_build_goto (disp_var); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
static bool shrink_wrap_one_built_in_call (gimple bi_call) { gimple_stmt_iterator bi_call_bsi; basic_block bi_call_bb, join_tgt_bb, guard_bb, guard_bb0; edge join_tgt_in_edge_from_call, join_tgt_in_edge_fall_thru; edge bi_call_in_edge0, guard_bb_in_edge; unsigned tn_cond_stmts, nconds; unsigned ci; gimple cond_expr = NULL; gimple cond_expr_start; tree bi_call_label_decl; gimple bi_call_label; auto_vec<gimple, 12> conds; gen_shrink_wrap_conditions (bi_call, conds, &nconds); /* This can happen if the condition generator decides it is not beneficial to do the transformation. Just return false and do not do any transformation for the call. */ if (nconds == 0) return false; bi_call_bb = gimple_bb (bi_call); /* Now find the join target bb -- split bi_call_bb if needed. */ if (stmt_ends_bb_p (bi_call)) { /* If the call must be the last in the bb, don't split the block, it could e.g. have EH edges. */ join_tgt_in_edge_from_call = find_fallthru_edge (bi_call_bb->succs); if (join_tgt_in_edge_from_call == NULL) return false; } else join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call); bi_call_bsi = gsi_for_stmt (bi_call); join_tgt_bb = join_tgt_in_edge_from_call->dest; /* Now it is time to insert the first conditional expression into bi_call_bb and split this bb so that bi_call is shrink-wrapped. */ tn_cond_stmts = conds.length (); cond_expr = NULL; cond_expr_start = conds[0]; for (ci = 0; ci < tn_cond_stmts; ci++) { gimple c = conds[ci]; gcc_assert (c || ci != 0); if (!c) break; gsi_insert_before (&bi_call_bsi, c, GSI_SAME_STMT); cond_expr = c; } nconds--; ci++; gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND); /* Now the label. */ bi_call_label_decl = create_artificial_label (gimple_location (bi_call)); bi_call_label = gimple_build_label (bi_call_label_decl); gsi_insert_before (&bi_call_bsi, bi_call_label, GSI_SAME_STMT); bi_call_in_edge0 = split_block (bi_call_bb, cond_expr); bi_call_in_edge0->flags &= ~EDGE_FALLTHRU; bi_call_in_edge0->flags |= EDGE_TRUE_VALUE; guard_bb0 = bi_call_bb; bi_call_bb = bi_call_in_edge0->dest; join_tgt_in_edge_fall_thru = make_edge (guard_bb0, join_tgt_bb, EDGE_FALSE_VALUE); bi_call_in_edge0->probability = REG_BR_PROB_BASE * ERR_PROB; bi_call_in_edge0->count = apply_probability (guard_bb0->count, bi_call_in_edge0->probability); join_tgt_in_edge_fall_thru->probability = inverse_probability (bi_call_in_edge0->probability); join_tgt_in_edge_fall_thru->count = guard_bb0->count - bi_call_in_edge0->count; /* Code generation for the rest of the conditions */ guard_bb = guard_bb0; while (nconds > 0) { unsigned ci0; edge bi_call_in_edge; gimple_stmt_iterator guard_bsi = gsi_for_stmt (cond_expr_start); ci0 = ci; cond_expr_start = conds[ci0]; for (; ci < tn_cond_stmts; ci++) { gimple c = conds[ci]; gcc_assert (c || ci != ci0); if (!c) break; gsi_insert_before (&guard_bsi, c, GSI_SAME_STMT); cond_expr = c; } nconds--; ci++; gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND); guard_bb_in_edge = split_block (guard_bb, cond_expr); guard_bb_in_edge->flags &= ~EDGE_FALLTHRU; guard_bb_in_edge->flags |= EDGE_FALSE_VALUE; bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_TRUE_VALUE); bi_call_in_edge->probability = REG_BR_PROB_BASE * ERR_PROB; bi_call_in_edge->count = apply_probability (guard_bb->count, bi_call_in_edge->probability); guard_bb_in_edge->probability = inverse_probability (bi_call_in_edge->probability); guard_bb_in_edge->count = guard_bb->count - bi_call_in_edge->count; } if (dump_file && (dump_flags & TDF_DETAILS)) { location_t loc; loc = gimple_location (bi_call); fprintf (dump_file, "%s:%d: note: function call is shrink-wrapped" " into error conditions.\n", LOCATION_FILE (loc), LOCATION_LINE (loc)); } return true; }
static tree cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) { tree defparm, parm, t; int i = 0; int nargs; tree *argarray; if (fn == NULL) return NULL; nargs = list_length (DECL_ARGUMENTS (fn)); argarray = (tree *) alloca (nargs * sizeof (tree)); defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); if (arg2) defparm = TREE_CHAIN (defparm); 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; 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 = build2 (POINTER_PLUS_EXPR, TREE_TYPE (start1), start1, end1); p1 = create_tmp_var (TREE_TYPE (start1), NULL); t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, start1); append_to_statement_list (t, &ret); if (arg2) { p2 = create_tmp_var (TREE_TYPE (start2), NULL); t = build2 (MODIFY_EXPR, TREE_TYPE (p2), 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); argarray[i++] = p1; if (arg2) argarray[i++] = p2; /* Handle default arguments. */ for (parm = defparm; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++) argarray[i] = convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i); t = build_call_a (fn, i, argarray); t = fold_convert (void_type_node, t); t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); append_to_statement_list (t, &ret); t = TYPE_SIZE_UNIT (inner_type); t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (p1), p1, t); t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, t); append_to_statement_list (t, &ret); if (arg2) { t = TYPE_SIZE_UNIT (inner_type); t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (p2), p2, t); t = build2 (MODIFY_EXPR, TREE_TYPE (p2), 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 { argarray[i++] = build_fold_addr_expr (arg1); if (arg2) argarray[i++] = build_fold_addr_expr (arg2); /* Handle default arguments. */ for (parm = defparm; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++) argarray[i] = convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i); t = build_call_a (fn, i, argarray); t = fold_convert (void_type_node, t); return fold_build_cleanup_point_expr (TREE_TYPE (t), t); } }
static gimple_seq gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first) { gimple top, entry, stmt; gimple_seq stmt_list, body_seq, incr_seq, exit_seq; tree cont_block, break_block; location_t stmt_locus; stmt_locus = input_location; stmt_list = NULL; body_seq = NULL; incr_seq = NULL; exit_seq = NULL; entry = NULL; break_block = begin_bc_block (bc_break); cont_block = begin_bc_block (bc_continue); /* If condition is zero don't generate a loop construct. */ if (cond && integer_zerop (cond)) { top = NULL; if (cond_is_first) { stmt = gimple_build_goto (get_bc_label (bc_break)); gimple_set_location (stmt, stmt_locus); gimple_seq_add_stmt (&stmt_list, stmt); } } else { /* If we use a LOOP_EXPR here, we have to feed the whole thing back through the main gimplifier to lower it. Given that we have to gimplify the loop body NOW so that we can resolve break/continue stmts, seems easier to just expand to gotos. */ top = gimple_build_label (create_artificial_label ()); /* If we have an exit condition, then we build an IF with gotos either out of the loop, or to the top of it. If there's no exit condition, then we just build a jump back to the top. */ if (cond && !integer_nonzerop (cond)) { if (cond != error_mark_node) { gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue); stmt = gimple_build_cond (NE_EXPR, cond, build_int_cst (TREE_TYPE (cond), 0), gimple_label_label (top), get_bc_label (bc_break)); gimple_seq_add_stmt (&exit_seq, stmt); } if (cond_is_first) { if (incr) { entry = gimple_build_label (create_artificial_label ()); stmt = gimple_build_goto (gimple_label_label (entry)); } else stmt = gimple_build_goto (get_bc_label (bc_continue)); gimple_set_location (stmt, stmt_locus); gimple_seq_add_stmt (&stmt_list, stmt); } } else { stmt = gimple_build_goto (gimple_label_label (top)); gimple_seq_add_stmt (&exit_seq, stmt); } } gimplify_stmt (&body, &body_seq); gimplify_stmt (&incr, &incr_seq); body_seq = finish_bc_block (bc_continue, cont_block, body_seq); gimple_seq_add_stmt (&stmt_list, top); gimple_seq_add_seq (&stmt_list, body_seq); gimple_seq_add_seq (&stmt_list, incr_seq); gimple_seq_add_stmt (&stmt_list, entry); gimple_seq_add_seq (&stmt_list, exit_seq); annotate_all_with_location (stmt_list, stmt_locus); return finish_bc_block (bc_break, break_block, stmt_list); }
static void genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, tree incr, bool cond_is_first, int *walk_subtrees, void *data) { tree blab, clab; tree entry = NULL, exit = NULL, t; tree stmt_list = NULL; blab = begin_bc_block (bc_break, start_locus); clab = begin_bc_block (bc_continue, start_locus); if (incr && EXPR_P (incr)) SET_EXPR_LOCATION (incr, start_locus); cp_walk_tree (&cond, cp_genericize_r, data, NULL); cp_walk_tree (&body, cp_genericize_r, data, NULL); cp_walk_tree (&incr, cp_genericize_r, data, NULL); *walk_subtrees = 0; /* If condition is zero don't generate a loop construct. */ if (cond && integer_zerop (cond)) { if (cond_is_first) { t = build1_loc (start_locus, GOTO_EXPR, void_type_node, get_bc_label (bc_break)); append_to_statement_list (t, &stmt_list); } } else { /* Expand to gotos, just like c_finish_loop. TODO: Use LOOP_EXPR. */ tree top = build1 (LABEL_EXPR, void_type_node, create_artificial_label (start_locus)); /* If we have an exit condition, then we build an IF with gotos either out of the loop, or to the top of it. If there's no exit condition, then we just build a jump back to the top. */ exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top)); if (cond && !integer_nonzerop (cond)) { /* Canonicalize the loop condition to the end. This means generating a branch to the loop condition. Reuse the continue label, if possible. */ if (cond_is_first) { if (incr) { entry = build1 (LABEL_EXPR, void_type_node, create_artificial_label (start_locus)); t = build1_loc (start_locus, GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (entry)); } else t = build1_loc (start_locus, GOTO_EXPR, void_type_node, get_bc_label (bc_continue)); append_to_statement_list (t, &stmt_list); } t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break)); exit = fold_build3_loc (start_locus, COND_EXPR, void_type_node, cond, exit, t); } append_to_statement_list (top, &stmt_list); } append_to_statement_list (body, &stmt_list); finish_bc_block (&stmt_list, bc_continue, clab); append_to_statement_list (incr, &stmt_list); append_to_statement_list (entry, &stmt_list); append_to_statement_list (exit, &stmt_list); finish_bc_block (&stmt_list, bc_break, blab); if (stmt_list == NULL_TREE) stmt_list = build1 (NOP_EXPR, void_type_node, integer_zero_node); *stmt_p = stmt_list; }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple *g; /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL these builtins are modelled as non-local label jumps to the label that is passed to these two builtins, so pretend we have a non-local label during GIMPLE passes too. See PR60003. */ cfun->has_nonlocal_label = 1; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; tree orig_dest = dest = gimple_call_lhs (stmt); if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME) dest = create_tmp_reg (TREE_TYPE (orig_dest)); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build orig_dest = dest if necessary. */ if (dest != orig_dest) { g = gimple_build_assign (orig_dest, dest); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }
static tree cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) { tree defparm, parm; int i; if (fn == NULL) return NULL; defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); if (arg2) defparm = TREE_CHAIN (defparm); 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 = tree_cons (NULL, p1, NULL); if (arg2) t = tree_cons (NULL, p2, t); /* Handle default arguments. */ i = 1 + (arg2 != NULL); for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i++), t); t = build_call (fn, nreverse (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 = tree_cons (NULL, build_fold_addr_expr (arg1), NULL); if (arg2) t = tree_cons (NULL, build_fold_addr_expr (arg2), t); /* Handle default arguments. */ i = 1 + (arg2 != NULL); for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i++), t); return build_call (fn, nreverse (t)); } }