aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.1/gcc/gimple-low.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.1/gcc/gimple-low.c')
-rw-r--r--gcc-4.8.1/gcc/gimple-low.c1030
1 files changed, 0 insertions, 1030 deletions
diff --git a/gcc-4.8.1/gcc/gimple-low.c b/gcc-4.8.1/gcc/gimple-low.c
deleted file mode 100644
index b06d194da..000000000
--- a/gcc-4.8.1/gcc/gimple-low.c
+++ /dev/null
@@ -1,1030 +0,0 @@
-/* GIMPLE lowering pass. Converts High GIMPLE into Low GIMPLE.
-
- Copyright (C) 2003-2013 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "gimple.h"
-#include "tree-iterator.h"
-#include "tree-inline.h"
-#include "tree-flow.h"
-#include "flags.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "tree-pass.h"
-#include "langhooks.h"
-
-/* The differences between High GIMPLE and Low GIMPLE are the
- following:
-
- 1- Lexical scopes are removed (i.e., GIMPLE_BIND disappears).
-
- 2- GIMPLE_TRY and GIMPLE_CATCH are converted to abnormal control
- flow and exception regions are built as an on-the-side region
- hierarchy (See tree-eh.c:lower_eh_constructs).
-
- 3- Multiple identical return statements are grouped into a single
- return and gotos to the unique return site. */
-
-/* Match a return statement with a label. During lowering, we identify
- identical return statements and replace duplicates with a jump to
- the corresponding label. */
-struct return_statements_t
-{
- tree label;
- gimple stmt;
-};
-typedef struct return_statements_t return_statements_t;
-
-
-struct lower_data
-{
- /* Block the current statement belongs to. */
- tree block;
-
- /* A vector of label and return statements to be moved to the end
- of the function. */
- vec<return_statements_t> return_statements;
-
- /* True if the current statement cannot fall through. */
- bool cannot_fallthru;
-
- /* True if the function calls __builtin_setjmp. */
- bool calls_builtin_setjmp;
-};
-
-static void lower_stmt (gimple_stmt_iterator *, struct lower_data *);
-static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
-static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *);
-static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *);
-static void lower_builtin_setjmp (gimple_stmt_iterator *);
-
-
-/* Lower the body of current_function_decl from High GIMPLE into Low
- GIMPLE. */
-
-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;
-}
-
-struct gimple_opt_pass pass_lower_cf =
-{
- {
- GIMPLE_PASS,
- "lower", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- NULL, /* gate */
- lower_function_body, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- PROP_gimple_any, /* properties_required */
- PROP_gimple_lcf, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
-
-
-
-/* Verify if the type of the argument matches that of the function
- declaration. If we cannot verify this or there is a mismatch,
- return false. */
-
-static bool
-gimple_check_call_args (gimple stmt, tree fndecl)
-{
- tree parms, p;
- unsigned int i, nargs;
-
- /* Calls to internal functions always match their signature. */
- if (gimple_call_internal_p (stmt))
- return true;
-
- nargs = gimple_call_num_args (stmt);
-
- /* Get argument types for verification. */
- if (fndecl)
- parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
- else
- parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
-
- /* Verify if the type of the argument matches that of the function
- declaration. If we cannot verify this or there is a mismatch,
- return false. */
- if (fndecl && DECL_ARGUMENTS (fndecl))
- {
- for (i = 0, p = DECL_ARGUMENTS (fndecl);
- i < nargs;
- i++, p = DECL_CHAIN (p))
- {
- tree arg;
- /* We cannot distinguish a varargs function from the case
- of excess parameters, still deferring the inlining decision
- to the callee is possible. */
- if (!p)
- break;
- arg = gimple_call_arg (stmt, i);
- if (p == error_mark_node
- || arg == error_mark_node
- || (!types_compatible_p (DECL_ARG_TYPE (p), TREE_TYPE (arg))
- && !fold_convertible_p (DECL_ARG_TYPE (p), arg)))
- return false;
- }
- }
- else if (parms)
- {
- for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
- {
- tree arg;
- /* If this is a varargs function defer inlining decision
- to callee. */
- if (!p)
- break;
- arg = gimple_call_arg (stmt, i);
- if (TREE_VALUE (p) == error_mark_node
- || arg == error_mark_node
- || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
- || (!types_compatible_p (TREE_VALUE (p), TREE_TYPE (arg))
- && !fold_convertible_p (TREE_VALUE (p), arg)))
- return false;
- }
- }
- else
- {
- if (nargs != 0)
- return false;
- }
- return true;
-}
-
-/* Verify if the type of the argument and lhs of CALL_STMT matches
- that of the function declaration CALLEE.
- If we cannot verify this or there is a mismatch, return false. */
-
-bool
-gimple_check_call_matching_types (gimple call_stmt, tree callee)
-{
- tree lhs;
-
- if ((DECL_RESULT (callee)
- && !DECL_BY_REFERENCE (DECL_RESULT (callee))
- && (lhs = gimple_call_lhs (call_stmt)) != NULL_TREE
- && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
- TREE_TYPE (lhs))
- && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
- || !gimple_check_call_args (call_stmt, callee))
- return false;
- return true;
-}
-
-/* Lower sequence SEQ. 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. */
-
-static void
-lower_sequence (gimple_seq *seq, struct lower_data *data)
-{
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start (*seq); !gsi_end_p (gsi); )
- lower_stmt (&gsi, data);
-}
-
-
-/* Lower the OpenMP directive statement pointed by GSI. DATA is
- passed through the recursion. */
-
-static void
-lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
-{
- gimple stmt;
-
- stmt = gsi_stmt (*gsi);
-
- lower_sequence (gimple_omp_body_ptr (stmt), data);
- gsi_insert_seq_after (gsi, gimple_omp_body (stmt), GSI_CONTINUE_LINKING);
- gimple_omp_set_body (stmt, NULL);
- gsi_next (gsi);
-}
-
-
-/* Lower statement GSI. DATA is passed through the recursion. We try to
- track the fallthruness of statements and get rid of unreachable return
- statements in order to prevent the EH lowering pass from adding useless
- edges that can cause bogus warnings to be issued later; this guess need
- not be 100% accurate, simply be conservative and reset cannot_fallthru
- to false if we don't know. */
-
-static void
-lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
-{
- gimple stmt = gsi_stmt (*gsi);
-
- gimple_set_block (stmt, data->block);
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_BIND:
- lower_gimple_bind (gsi, data);
- /* Propagate fallthruness. */
- return;
-
- case GIMPLE_COND:
- case GIMPLE_GOTO:
- case GIMPLE_SWITCH:
- data->cannot_fallthru = true;
- gsi_next (gsi);
- return;
-
- case GIMPLE_RETURN:
- if (data->cannot_fallthru)
- {
- gsi_remove (gsi, false);
- /* Propagate fallthruness. */
- }
- else
- {
- lower_gimple_return (gsi, data);
- data->cannot_fallthru = true;
- }
- return;
-
- case GIMPLE_TRY:
- if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
- lower_try_catch (gsi, data);
- else
- {
- /* It must be a GIMPLE_TRY_FINALLY. */
- bool cannot_fallthru;
- lower_sequence (gimple_try_eval_ptr (stmt), data);
- cannot_fallthru = data->cannot_fallthru;
-
- /* The finally clause is always executed after the try clause,
- so if it does not fall through, then the try-finally will not
- fall through. Otherwise, if the try clause does not fall
- through, then when the finally clause falls through it will
- resume execution wherever the try clause was going. So the
- whole try-finally will only fall through if both the try
- clause and the finally clause fall through. */
- data->cannot_fallthru = false;
- lower_sequence (gimple_try_cleanup_ptr (stmt), data);
- data->cannot_fallthru |= cannot_fallthru;
- gsi_next (gsi);
- }
- return;
-
- case GIMPLE_EH_ELSE:
- lower_sequence (gimple_eh_else_n_body_ptr (stmt), data);
- lower_sequence (gimple_eh_else_e_body_ptr (stmt), data);
- break;
-
- case GIMPLE_NOP:
- case GIMPLE_ASM:
- case GIMPLE_ASSIGN:
- case GIMPLE_PREDICT:
- case GIMPLE_LABEL:
- case GIMPLE_EH_MUST_NOT_THROW:
- case GIMPLE_OMP_FOR:
- case GIMPLE_OMP_SECTIONS:
- case GIMPLE_OMP_SECTIONS_SWITCH:
- case GIMPLE_OMP_SECTION:
- case GIMPLE_OMP_SINGLE:
- case GIMPLE_OMP_MASTER:
- case GIMPLE_OMP_ORDERED:
- case GIMPLE_OMP_CRITICAL:
- case GIMPLE_OMP_RETURN:
- case GIMPLE_OMP_ATOMIC_LOAD:
- case GIMPLE_OMP_ATOMIC_STORE:
- case GIMPLE_OMP_CONTINUE:
- break;
-
- case GIMPLE_CALL:
- {
- tree decl = gimple_call_fndecl (stmt);
- unsigned i;
-
- for (i = 0; i < gimple_call_num_args (stmt); i++)
- {
- tree arg = gimple_call_arg (stmt, i);
- if (EXPR_P (arg))
- TREE_SET_BLOCK (arg, data->block);
- }
-
- if (decl
- && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
- && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
- {
- lower_builtin_setjmp (gsi);
- data->cannot_fallthru = false;
- data->calls_builtin_setjmp = true;
- return;
- }
-
- if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN))
- {
- data->cannot_fallthru = true;
- gsi_next (gsi);
- return;
- }
- }
- break;
-
- case GIMPLE_OMP_PARALLEL:
- case GIMPLE_OMP_TASK:
- data->cannot_fallthru = false;
- lower_omp_directive (gsi, data);
- data->cannot_fallthru = false;
- return;
-
- case GIMPLE_TRANSACTION:
- lower_sequence (gimple_transaction_body_ptr (stmt), data);
- break;
-
- default:
- gcc_unreachable ();
- }
-
- data->cannot_fallthru = false;
- gsi_next (gsi);
-}
-
-/* Lower a bind_expr TSI. DATA is passed through the recursion. */
-
-static void
-lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
-{
- tree old_block = data->block;
- gimple stmt = gsi_stmt (*gsi);
- tree new_block = gimple_bind_block (stmt);
-
- if (new_block)
- {
- if (new_block == old_block)
- {
- /* The outermost block of the original function may not be the
- outermost statement chain of the gimplified function. So we
- may see the outermost block just inside the function. */
- gcc_assert (new_block == DECL_INITIAL (current_function_decl));
- new_block = NULL;
- }
- else
- {
- /* We do not expect to handle duplicate blocks. */
- gcc_assert (!TREE_ASM_WRITTEN (new_block));
- TREE_ASM_WRITTEN (new_block) = 1;
-
- /* Block tree may get clobbered by inlining. Normally this would
- be fixed in rest_of_decl_compilation using block notes, but
- since we are not going to emit them, it is up to us. */
- BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block);
- BLOCK_SUBBLOCKS (old_block) = new_block;
- BLOCK_SUBBLOCKS (new_block) = NULL_TREE;
- BLOCK_SUPERCONTEXT (new_block) = old_block;
-
- data->block = new_block;
- }
- }
-
- record_vars (gimple_bind_vars (stmt));
- lower_sequence (gimple_bind_body_ptr (stmt), data);
-
- if (new_block)
- {
- gcc_assert (data->block == new_block);
-
- BLOCK_SUBBLOCKS (new_block)
- = blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
- data->block = old_block;
- }
-
- /* The GIMPLE_BIND no longer carries any useful information -- kill it. */
- gsi_insert_seq_before (gsi, gimple_bind_body (stmt), GSI_SAME_STMT);
- gsi_remove (gsi, false);
-}
-
-/* Same as above, but for a GIMPLE_TRY_CATCH. */
-
-static void
-lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
-{
- bool cannot_fallthru;
- gimple stmt = gsi_stmt (*gsi);
- gimple_stmt_iterator i;
-
- /* We don't handle GIMPLE_TRY_FINALLY. */
- gcc_assert (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH);
-
- lower_sequence (gimple_try_eval_ptr (stmt), data);
- cannot_fallthru = data->cannot_fallthru;
-
- i = gsi_start (*gimple_try_cleanup_ptr (stmt));
- switch (gimple_code (gsi_stmt (i)))
- {
- case GIMPLE_CATCH:
- /* We expect to see a sequence of GIMPLE_CATCH stmts, each with a
- catch expression and a body. The whole try/catch may fall
- through iff any of the catch bodies falls through. */
- for (; !gsi_end_p (i); gsi_next (&i))
- {
- data->cannot_fallthru = false;
- lower_sequence (gimple_catch_handler_ptr (gsi_stmt (i)), data);
- if (!data->cannot_fallthru)
- cannot_fallthru = false;
- }
- break;
-
- case GIMPLE_EH_FILTER:
- /* The exception filter expression only matters if there is an
- exception. If the exception does not match EH_FILTER_TYPES,
- we will execute EH_FILTER_FAILURE, and we will fall through
- if that falls through. If the exception does match
- EH_FILTER_TYPES, the stack unwinder will continue up the
- stack, so we will not fall through. We don't know whether we
- will throw an exception which matches EH_FILTER_TYPES or not,
- so we just ignore EH_FILTER_TYPES and assume that we might
- throw an exception which doesn't match. */
- data->cannot_fallthru = false;
- lower_sequence (gimple_eh_filter_failure_ptr (gsi_stmt (i)), data);
- if (!data->cannot_fallthru)
- cannot_fallthru = false;
- break;
-
- default:
- /* This case represents statements to be executed when an
- exception occurs. Those statements are implicitly followed
- by a GIMPLE_RESX to resume execution after the exception. So
- in this case the try/catch never falls through. */
- data->cannot_fallthru = false;
- lower_sequence (gimple_try_cleanup_ptr (stmt), data);
- break;
- }
-
- data->cannot_fallthru = cannot_fallthru;
- gsi_next (gsi);
-}
-
-/* Try to determine whether a TRY_CATCH expression can fall through.
- This is a subroutine of block_may_fallthru. */
-
-static bool
-try_catch_may_fallthru (const_tree stmt)
-{
- tree_stmt_iterator i;
-
- /* If the TRY block can fall through, the whole TRY_CATCH can
- fall through. */
- if (block_may_fallthru (TREE_OPERAND (stmt, 0)))
- return true;
-
- i = tsi_start (TREE_OPERAND (stmt, 1));
- switch (TREE_CODE (tsi_stmt (i)))
- {
- case CATCH_EXPR:
- /* We expect to see a sequence of CATCH_EXPR trees, each with a
- catch expression and a body. The whole TRY_CATCH may fall
- through iff any of the catch bodies falls through. */
- for (; !tsi_end_p (i); tsi_next (&i))
- {
- if (block_may_fallthru (CATCH_BODY (tsi_stmt (i))))
- return true;
- }
- return false;
-
- case EH_FILTER_EXPR:
- /* The exception filter expression only matters if there is an
- exception. If the exception does not match EH_FILTER_TYPES,
- we will execute EH_FILTER_FAILURE, and we will fall through
- if that falls through. If the exception does match
- EH_FILTER_TYPES, the stack unwinder will continue up the
- stack, so we will not fall through. We don't know whether we
- will throw an exception which matches EH_FILTER_TYPES or not,
- so we just ignore EH_FILTER_TYPES and assume that we might
- throw an exception which doesn't match. */
- return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i)));
-
- default:
- /* This case represents statements to be executed when an
- exception occurs. Those statements are implicitly followed
- by a RESX statement to resume execution after the exception.
- So in this case the TRY_CATCH never falls through. */
- return false;
- }
-}
-
-
-/* Same as above, but for a GIMPLE_TRY_CATCH. */
-
-static bool
-gimple_try_catch_may_fallthru (gimple stmt)
-{
- gimple_stmt_iterator i;
-
- /* We don't handle GIMPLE_TRY_FINALLY. */
- gcc_assert (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH);
-
- /* If the TRY block can fall through, the whole TRY_CATCH can
- fall through. */
- if (gimple_seq_may_fallthru (gimple_try_eval (stmt)))
- return true;
-
- i = gsi_start (*gimple_try_cleanup_ptr (stmt));
- switch (gimple_code (gsi_stmt (i)))
- {
- case GIMPLE_CATCH:
- /* We expect to see a sequence of GIMPLE_CATCH stmts, each with a
- catch expression and a body. The whole try/catch may fall
- through iff any of the catch bodies falls through. */
- for (; !gsi_end_p (i); gsi_next (&i))
- {
- if (gimple_seq_may_fallthru (gimple_catch_handler (gsi_stmt (i))))
- return true;
- }
- return false;
-
- case GIMPLE_EH_FILTER:
- /* The exception filter expression only matters if there is an
- exception. If the exception does not match EH_FILTER_TYPES,
- we will execute EH_FILTER_FAILURE, and we will fall through
- if that falls through. If the exception does match
- EH_FILTER_TYPES, the stack unwinder will continue up the
- stack, so we will not fall through. We don't know whether we
- will throw an exception which matches EH_FILTER_TYPES or not,
- so we just ignore EH_FILTER_TYPES and assume that we might
- throw an exception which doesn't match. */
- return gimple_seq_may_fallthru (gimple_eh_filter_failure (gsi_stmt (i)));
-
- default:
- /* This case represents statements to be executed when an
- exception occurs. Those statements are implicitly followed
- by a GIMPLE_RESX to resume execution after the exception. So
- in this case the try/catch never falls through. */
- return false;
- }
-}
-
-
-/* Try to determine if we can fall out of the bottom of BLOCK. This guess
- need not be 100% accurate; simply be conservative and return true if we
- don't know. This is used only to avoid stupidly generating extra code.
- If we're wrong, we'll just delete the extra code later. */
-
-bool
-block_may_fallthru (const_tree block)
-{
- /* This CONST_CAST is okay because expr_last returns its argument
- unmodified and we assign it to a const_tree. */
- const_tree stmt = expr_last (CONST_CAST_TREE(block));
-
- switch (stmt ? TREE_CODE (stmt) : ERROR_MARK)
- {
- case GOTO_EXPR:
- case RETURN_EXPR:
- /* Easy cases. If the last statement of the block implies
- control transfer, then we can't fall through. */
- return false;
-
- case SWITCH_EXPR:
- /* If SWITCH_LABELS is set, this is lowered, and represents a
- branch to a selected label and hence can not fall through.
- Otherwise SWITCH_BODY is set, and the switch can fall
- through. */
- return SWITCH_LABELS (stmt) == NULL_TREE;
-
- case COND_EXPR:
- if (block_may_fallthru (COND_EXPR_THEN (stmt)))
- return true;
- return block_may_fallthru (COND_EXPR_ELSE (stmt));
-
- case BIND_EXPR:
- return block_may_fallthru (BIND_EXPR_BODY (stmt));
-
- case TRY_CATCH_EXPR:
- return try_catch_may_fallthru (stmt);
-
- case TRY_FINALLY_EXPR:
- /* The finally clause is always executed after the try clause,
- so if it does not fall through, then the try-finally will not
- fall through. Otherwise, if the try clause does not fall
- through, then when the finally clause falls through it will
- resume execution wherever the try clause was going. So the
- whole try-finally will only fall through if both the try
- clause and the finally clause fall through. */
- 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);
- else
- return true;
- /* FALLTHRU */
-
- case CALL_EXPR:
- /* Functions that do not return do not fall through. */
- return (call_expr_flags (stmt) & ECF_NORETURN) == 0;
-
- case CLEANUP_POINT_EXPR:
- return block_may_fallthru (TREE_OPERAND (stmt, 0));
-
- case TARGET_EXPR:
- return block_may_fallthru (TREE_OPERAND (stmt, 1));
-
- case ERROR_MARK:
- return true;
-
- default:
- return lang_hooks.block_may_fallthru (stmt);
- }
-}
-
-
-/* Try to determine if we can continue executing the statement
- immediately following STMT. This guess need not be 100% accurate;
- simply be conservative and return true if we don't know. This is
- used only to avoid stupidly generating extra code. If we're wrong,
- we'll just delete the extra code later. */
-
-bool
-gimple_stmt_may_fallthru (gimple stmt)
-{
- if (!stmt)
- return true;
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_GOTO:
- case GIMPLE_RETURN:
- case GIMPLE_RESX:
- /* Easy cases. If the last statement of the seq implies
- control transfer, then we can't fall through. */
- return false;
-
- case GIMPLE_SWITCH:
- /* Switch has already been lowered and represents a branch
- to a selected label and hence can't fall through. */
- return false;
-
- case GIMPLE_COND:
- /* GIMPLE_COND's are already lowered into a two-way branch. They
- can't fall through. */
- return false;
-
- case GIMPLE_BIND:
- return gimple_seq_may_fallthru (gimple_bind_body (stmt));
-
- case GIMPLE_TRY:
- if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
- return gimple_try_catch_may_fallthru (stmt);
-
- /* It must be a GIMPLE_TRY_FINALLY. */
-
- /* The finally clause is always executed after the try clause,
- so if it does not fall through, then the try-finally will not
- fall through. Otherwise, if the try clause does not fall
- through, then when the finally clause falls through it will
- resume execution wherever the try clause was going. So the
- whole try-finally will only fall through if both the try
- clause and the finally clause fall through. */
- return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
- && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
-
- case GIMPLE_EH_ELSE:
- return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
- || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));
-
- case GIMPLE_CALL:
- /* Functions that do not return do not fall through. */
- return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
-
- default:
- return true;
- }
-}
-
-
-/* Same as gimple_stmt_may_fallthru, but for the gimple sequence SEQ. */
-
-bool
-gimple_seq_may_fallthru (gimple_seq seq)
-{
- return gimple_stmt_may_fallthru (gimple_seq_last_stmt (seq));
-}
-
-
-/* Lower a GIMPLE_RETURN GSI. DATA is passed through the recursion. */
-
-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);
-}
-
-/* Lower a __builtin_setjmp GSI.
-
- __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 (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);
-}
-
-
-/* Record the variables in VARS into function FN. */
-
-void
-record_vars_into (tree vars, tree fn)
-{
- bool change_cfun = fn != current_function_decl;
-
- if (change_cfun)
- push_cfun (DECL_STRUCT_FUNCTION (fn));
-
- for (; vars; vars = DECL_CHAIN (vars))
- {
- tree var = vars;
-
- /* BIND_EXPRs contains also function/type/constant declarations
- we don't need to care about. */
- if (TREE_CODE (var) != VAR_DECL)
- continue;
-
- /* Nothing to do in this case. */
- if (DECL_EXTERNAL (var))
- continue;
-
- /* Record the variable. */
- add_local_decl (cfun, var);
- }
-
- if (change_cfun)
- pop_cfun ();
-}
-
-
-/* Record the variables in VARS into current_function_decl. */
-
-void
-record_vars (tree vars)
-{
- record_vars_into (vars, current_function_decl);
-}