diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-09-29 06:32:58 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-09-29 06:32:58 +0000 |
commit | 2c8a1497c34d993b24a00f9962f72ab05d749471 (patch) | |
tree | c8e2772aad71fdf66dba0112c42b9178748e598f /gcc/gimple-low.c | |
parent | fc4a9273d580b8ed8519c3349130a73bda16c5b9 (diff) | |
download | gcc-2c8a1497c34d993b24a00f9962f72ab05d749471.tar.gz |
* builtins.c (expand_builtin_setjmp): Delete.
(expand_builtin) <BUILT_IN_SETJMP>: Mark as unreachable.
<BUILT_IN_SETJMP_SETUP>: New case.
<BUILT_IN_SETJMP_DISPATCHER>: Likewise.
<BUILT_IN_SETJMP_RECEIVER>: Likewise.
* builtins.def (BUILT_IN_SETJMP_SETUP): New built-in stub.
(BUILT_IN_SETJMP_DISPATCHER): Likewise.
(BUILT_IN_SETJMP_RECEIVER): Likewise.
* gimple-low.c (struct lower_data): New field calls_builtin_setjmp.
(lower_function_body): Initialize it to false. If it is set to true
at the end of the processing, emit the setjmp dispatcher.
(lower_stmt) <CALL_EXPR>: Invoke lower_builtin_setjmp if the callee
is __builtin_setjmp and set calls_builtin_setjmp to true as well.
<MODIFY_EXPR>: Fall through to above case if there is a CALL_EXPR
on the rhs of the assignment.
(lower_builtin_setjmp): New function.
* tree.c (build_common_builtin_nodes): Build BUILT_IN_SETJMP_SETUP,
BUILT_IN_SETJMP_DISPATCHER and BUILT_IN_SETJMP_RECEIVER nodes.
* tree-cfg.c (make_exit_edges) <CALL_EXPR>: Use specific predicate
to detect calls that can go to non-local labels. Use specific
helper to create the abnormal edges associated with them.
<MODIFY_EXPR>: Likewise.
(make_abnormal_goto_edges): New function extracted from...
(make_goto_expr_edges): ...here. Call it for computed gotos.
(simple_goto_p): Minor tweak.
(tree_can_make_abnormal_goto): New predicate.
(tree_redirect_edge_and_branch): Return zero on all abnormal edges.
(tree_purge_dead_abnormal_call_edges): New function.
* tree-flow.h (tree_can_make_abnormal_goto): Declare.
(tree_purge_dead_abnormal_call_edges): Likewise.
(make_abnormal_goto_edges): Likewise.
* tree-inline.c (expand_call_inline): Simplify statement frobbing.
Purge all dead abnormal edges if the call was in the last statement.
* tree-optimize.c (has_abnormal_outgoing_edge_p): New predicate.
(execute_fixup_cfg): If there are non-local labels in the function,
scan the basic blocks and split them at calls that can go to non-local
labels or add missing abnormal call edges. Write down the CFG in the
dump file.
(pass_fixup_cfg): Remove TODO_dump_func flag.
* unwind-sjlj.c: Poison setjmp.
* doc/install.texi (enable-sjlj-exceptions): Use more general wording.
* doc/tm.texi (DWARF2_UNWIND_INFO): Likewise.
(TARGET_UNWIND_TABLES_DEFAULT): Fix typo.
(DONT_USE_BUILTIN_SETJMP): Document it.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@117298 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple-low.c')
-rw-r--r-- | gcc/gimple-low.c | 191 |
1 files changed, 184 insertions, 7 deletions
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index ff6b8b27f30..c6a0312a2be 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -49,14 +49,18 @@ struct lower_data /* A TREE_LIST of label and return statements to be moved to the end of the function. */ tree return_statements; + + /* True if the function calls __builtin_setjmp. */ + bool calls_builtin_setjmp; }; static void lower_stmt (tree_stmt_iterator *, struct lower_data *); static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); static void lower_return_expr (tree_stmt_iterator *, struct lower_data *); +static void lower_builtin_setjmp (tree_stmt_iterator *); -/* Lowers the body of current_function_decl. */ +/* Lower the body of current_function_decl. */ static unsigned int lower_function_body (void) @@ -113,6 +117,35 @@ lower_function_body (void) tsi_link_after (&i, x, TSI_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 (); + /* This mark will create forward edges from every call site. */ + DECL_NONLOCAL (disp_label) = 1; + current_function_has_nonlocal_label = 1; + x = build1 (LABEL_EXPR, void_type_node, disp_label); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + + /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' + and insert. */ + disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); + t = build_addr (disp_label, current_function_decl); + arg = tree_cons (NULL, t, NULL); + t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER]; + t = build_function_call_expr (t,arg); + x = build2 (MODIFY_EXPR, void_type_node, disp_var, t); + + /* Build 'goto DISP_VAR;' and insert. */ + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + x = build1 (GOTO_EXPR, void_type_node, disp_var); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + } + gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); @@ -139,7 +172,7 @@ struct tree_opt_pass pass_lower_cf = }; -/* Lowers the EXPR. Unlike gimplification the statements are not relowered +/* Lower the EXPR. Unlike gimplification the statements are not relowered when they are changed -- if this has to be done, the lowering routine must do it explicitly. DATA is passed through the recursion. */ @@ -171,7 +204,7 @@ lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data) } -/* Lowers statement TSI. DATA is passed through the recursion. */ +/* Lower statement TSI. DATA is passed through the recursion. */ static void lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) @@ -207,8 +240,6 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) case NOP_EXPR: case ASM_EXPR: - case MODIFY_EXPR: - case CALL_EXPR: case GOTO_EXPR: case LABEL_EXPR: case SWITCH_EXPR: @@ -223,6 +254,27 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) case OMP_CONTINUE: break; + case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) + stmt = TREE_OPERAND (stmt, 1); + else + break; + /* FALLTHRU */ + + case CALL_EXPR: + { + tree decl = get_callee_fndecl (stmt); + if (decl + && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP) + { + data->calls_builtin_setjmp = true; + lower_builtin_setjmp (tsi); + return; + } + } + break; + case OMP_PARALLEL: lower_omp_directive (tsi, data); return; @@ -234,7 +286,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) tsi_next (tsi); } -/* Lowers a bind_expr TSI. DATA is passed through the recursion. */ +/* Lower a bind_expr TSI. DATA is passed through the recursion. */ static void lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) @@ -403,7 +455,7 @@ block_may_fallthru (tree block) } } -/* Lowers a cond_expr TSI. DATA is passed through the recursion. */ +/* Lower a cond_expr TSI. DATA is passed through the recursion. */ static void lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) @@ -498,6 +550,8 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) tsi_next (tsi); } +/* Lower a return_expr TSI. DATA is passed through the recursion. */ + static void lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) { @@ -534,6 +588,129 @@ lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) tsi_link_before (tsi, t, TSI_SAME_STMT); tsi_delink (tsi); } + +/* Lower a __builtin_setjmp TSI. + + __builtin_setjmp is passed a pointer to an array of five words (not + all will be used on all machines). It operates similarly to the C + library function of the same name, but is more efficient. + + It is lowered into 3 other builtins, namely __builtin_setjmp_setup, + __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with + __builtin_setjmp_dispatcher shared among all the instances; that's + why it is only emitted at the end by lower_function_body. + + After full lowering, the body of the function should look like: + + { + void * setjmpvar.0; + int D.1844; + int D.2844; + + [...] + + __builtin_setjmp_setup (&buf, &<D1847>); + D.1844 = 0; + goto <D1846>; + <D1847>:; + __builtin_setjmp_receiver (&<D1847>); + D.1844 = 1; + <D1846>:; + if (D.1844 == 0) goto <D1848>; else goto <D1849>; + + [...] + + __builtin_setjmp_setup (&buf, &<D2847>); + D.2844 = 0; + goto <D2846>; + <D2847>:; + __builtin_setjmp_receiver (&<D2847>); + D.2844 = 1; + <D2846>:; + if (D.2844 == 0) goto <D2848>; else goto <D2849>; + + [...] + + <D3850>:; + return; + <D3853>: [non-local]; + setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>); + goto setjmpvar.0; + } + + The dispatcher block will be both the unique destination of all the + abnormal call edges and the unique source of all the abnormal edges + to the receivers, thus keeping the complexity explosion localized. */ + +static void +lower_builtin_setjmp (tree_stmt_iterator *tsi) +{ + tree stmt = tsi_stmt (*tsi); + tree cont_label = create_artificial_label (); + tree next_label = create_artificial_label (); + tree dest, t, arg; + + /* 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; + + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + dest = TREE_OPERAND (stmt, 0); + stmt = TREE_OPERAND (stmt, 1); + } + else + dest = NULL_TREE; + + /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ + t = build_addr (next_label, current_function_decl); + arg = tree_cons (NULL, t, NULL); + t = TREE_VALUE (TREE_OPERAND (stmt, 1)); + arg = tree_cons (NULL, t, arg); + t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP]; + t = build_function_call_expr (t, arg); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build 'DEST = 0' and insert. */ + if (dest) + { + t = build2 (MODIFY_EXPR, void_type_node, dest, integer_zero_node); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + } + + /* Build 'goto CONT_LABEL' and insert. */ + t = build1 (GOTO_EXPR, void_type_node, cont_label); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build 'NEXT_LABEL:' and insert. */ + t = build1 (LABEL_EXPR, void_type_node, next_label); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ + t = build_addr (next_label, current_function_decl); + arg = tree_cons (NULL, t, NULL); + t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER]; + t = build_function_call_expr (t, arg); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build 'DEST = 1' and insert. */ + if (dest) + { + t = build2 (MODIFY_EXPR, void_type_node, dest, integer_one_node); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + } + + /* Build 'CONT_LABEL:' and insert. */ + t = build1 (LABEL_EXPR, void_type_node, cont_label); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Remove the call to __builtin_setjmp. */ + tsi_delink (tsi); +} /* Record the variables in VARS into function FN. */ |