void tree_rest_of_compilation (tree fndecl) { location_t saved_loc; timevar_push (TV_EXPAND); gcc_assert (cgraph_global_info_ready); /* Initialize the default bitmap obstack. */ bitmap_obstack_initialize (NULL); /* Initialize the RTL code for the function. */ current_function_decl = fndecl; saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (fndecl); init_function_start (fndecl); /* Even though we're inside a function body, we still don't want to call expand_expr to calculate the size of a variable-sized array. We haven't necessarily assigned RTL to all variables yet, so it's not safe to try to expand expressions involving them. */ cfun->dont_save_pending_sizes_p = 1; gimple_register_cfg_hooks (); bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/ execute_all_ipa_transforms (); /* Perform all tree transforms and optimizations. */ /* Signal the start of passes. */ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL); execute_pass_list (all_passes); /* Signal the end of passes. */ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL); bitmap_obstack_release (®_obstack); /* Release the default bitmap obstack. */ bitmap_obstack_release (NULL); set_cfun (NULL); /* If requested, warn about function definitions where the function will return a value (usually of some struct or union type) which itself will take up a lot of stack space. */ if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) { tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); if (ret_type && TYPE_SIZE_UNIT (ret_type) && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type), larger_than_size)) { unsigned int size_as_int = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) warning (OPT_Wlarger_than_eq, "size of return value of %q+D is %u bytes", fndecl, size_as_int); else warning (OPT_Wlarger_than_eq, "size of return value of %q+D is larger than %wd bytes", fndecl, larger_than_size); } } gimple_set_body (fndecl, NULL); if (DECL_STRUCT_FUNCTION (fndecl) == 0 && !cgraph_node (fndecl)->origin) { /* Stop pointing to the local nodes about to be freed. But DECL_INITIAL must remain nonzero so we know this was an actual function definition. For a nested function, this is done in c_pop_function_context. If rest_of_compilation set this to 0, leave it 0. */ if (DECL_INITIAL (fndecl) != 0) DECL_INITIAL (fndecl) = error_mark_node; } input_location = saved_loc; ggc_collect (); timevar_pop (TV_EXPAND); }
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; 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); } /* 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 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 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; 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 we had begin stmt markers from e.g. PCH, but this compilation doesn't want them, lower_stmt will have cleaned them up; we can now clear the flag that indicates we had them. */ if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) { /* This counter needs not be exact, but before lowering it will most certainly be. */ gcc_assert (cfun->debug_marker_count == 0); cfun->debug_nonbind_markers = false; } /* 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. */ bool may_fallthru = gimple_seq_may_fallthru (lowered_body); if (may_fallthru && (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); may_fallthru = false; } /* 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 (may_fallthru) { /* Remove the line number from the representative return statement. It now fills in for the fallthru too. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (t.stmt, UNKNOWN_LOCATION); may_fallthru = false; } } /* 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; }