X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;ds=sidebyside;f=gcc%2Fgimple-low.c;h=642cd4fdd5c0e92eaf91a100cc376687250e039a;hb=6776dec81181ac5268babea9d9e258e8c2ea02b7;hp=6de2b8f185550bf294a0e55efaf7093e6076d525;hpb=2a1990e9c656063ab626fab258ae2d418378c76d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 6de2b8f1855..642cd4fdd5c 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -1,6 +1,6 @@ /* Tree lowering pass. Lowers GIMPLE into unstructured form. - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -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,34 @@ 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"); + arg = build_addr (disp_label, current_function_decl); + t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER]; + t = build_call_expr (t, 1, arg); + x = build_gimple_modify_stmt (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 +171,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. */ @@ -159,14 +191,10 @@ lower_stmt_body (tree expr, struct lower_data *data) static void lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data) { - tree clause, stmt; + tree stmt; stmt = tsi_stmt (*tsi); - clause = (TREE_CODE (stmt) >= OMP_PARALLEL && TREE_CODE (stmt) <= OMP_SINGLE) - ? OMP_CLAUSES (stmt) - : NULL_TREE; - lower_stmt_body (OMP_BODY (stmt), data); tsi_link_before (tsi, stmt, TSI_SAME_STMT); tsi_link_before (tsi, OMP_BODY (stmt), TSI_SAME_STMT); @@ -175,7 +203,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) @@ -211,15 +239,9 @@ 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: - case OMP_RETURN_EXPR: - break; - - case OMP_PARALLEL: case OMP_FOR: case OMP_SECTIONS: case OMP_SECTION: @@ -227,6 +249,32 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) case OMP_MASTER: case OMP_ORDERED: case OMP_CRITICAL: + case OMP_RETURN: + case OMP_CONTINUE: + break; + + case GIMPLE_MODIFY_STMT: + if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR) + stmt = GIMPLE_STMT_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; @@ -237,7 +285,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) @@ -387,9 +435,9 @@ block_may_fallthru (tree block) return (block_may_fallthru (TREE_OPERAND (stmt, 0)) && block_may_fallthru (TREE_OPERAND (stmt, 1))); - case MODIFY_EXPR: - if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) - stmt = TREE_OPERAND (stmt, 1); + case GIMPLE_MODIFY_STMT: + if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR) + stmt = GIMPLE_STMT_OPERAND (stmt, 1); else return true; /* FALLTHRU */ @@ -406,7 +454,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) @@ -501,6 +549,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) { @@ -509,15 +559,15 @@ lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) /* Extract the value being returned. */ value = TREE_OPERAND (stmt, 0); - if (value && TREE_CODE (value) == MODIFY_EXPR) - value = TREE_OPERAND (value, 1); + if (value && TREE_CODE (value) == GIMPLE_MODIFY_STMT) + value = GIMPLE_STMT_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 (tvalue && TREE_CODE (tvalue) == GIMPLE_MODIFY_STMT) + tvalue = GIMPLE_STMT_OPERAND (tvalue, 1); if (value == tvalue) { @@ -537,6 +587,127 @@ 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, &); + D.1844 = 0; + goto ; + :; + __builtin_setjmp_receiver (&); + D.1844 = 1; + :; + if (D.1844 == 0) goto ; else goto ; + + [...] + + __builtin_setjmp_setup (&buf, &); + D.2844 = 0; + goto ; + :; + __builtin_setjmp_receiver (&); + D.2844 = 1; + :; + if (D.2844 == 0) goto ; else goto ; + + [...] + + :; + return; + : [non-local]; + setjmpvar.0 = __builtin_setjmp_dispatcher (&); + 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) == GIMPLE_MODIFY_STMT) + { + dest = GIMPLE_STMT_OPERAND (stmt, 0); + stmt = GIMPLE_STMT_OPERAND (stmt, 1); + } + else + dest = NULL_TREE; + + /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ + arg = build_addr (next_label, current_function_decl); + t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP]; + t = build_call_expr (t, 2, CALL_EXPR_ARG (stmt, 0), arg); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build 'DEST = 0' and insert. */ + if (dest) + { + t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (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. */ + arg = build_addr (next_label, current_function_decl); + t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER]; + t = build_call_expr (t, 1, arg); + SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); + tsi_link_before (tsi, t, TSI_SAME_STMT); + + /* Build 'DEST = 1' and insert. */ + if (dest) + { + t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (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. */