You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
-#include "errors.h"
#include "varray.h"
#include "tree-gimple.h"
#include "tree-inline.h"
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 bool expand_var_p (tree);
/* Lowers the body of current_function_decl. */
-static void
+static unsigned int
lower_function_body (void)
{
struct lower_data data;
gcc_assert (TREE_CODE (bind) == BIND_EXPR);
+ 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 = NULL_TREE;
-
*body_p = alloc_stmt_list ();
i = tsi_start (*body_p);
tsi_link_after (&i, bind, TSI_NEW_STMT);
&& (data.return_statements == NULL
|| TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL))
{
- x = build (RETURN_EXPR, void_type_node, NULL);
+ x = build1 (RETURN_EXPR, void_type_node, NULL);
SET_EXPR_LOCATION (x, cfun->function_end_locus);
tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
}
at the end of the function. */
for (t = data.return_statements ; t ; t = TREE_CHAIN (t))
{
- x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
+ x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
/* Remove the line number from the representative return statement.
= blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
clear_block_marks (data.block);
+ return 0;
}
struct tree_opt_pass pass_lower_cf =
0, /* tv_id */
PROP_gimple_any, /* properties_required */
PROP_gimple_lcf, /* properties_provided */
- PROP_gimple_any, /* properties_destroyed */
+ 0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
when they are changed -- if this has to be done, the lowering routine must
do it explicitly. DATA is passed through the recursion. */
-void
+static void
lower_stmt_body (tree expr, struct lower_data *data)
{
tree_stmt_iterator tsi;
lower_stmt (&tsi, data);
}
+
+/* Lower the OpenMP directive statement pointed by TSI. DATA is
+ passed through the recursion. */
+
+static void
+lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data)
+{
+ tree stmt;
+
+ stmt = tsi_stmt (*tsi);
+
+ 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);
+ OMP_BODY (stmt) = NULL_TREE;
+ tsi_delink (tsi);
+}
+
+
/* Lowers statement TSI. DATA is passed through the recursion. */
static void
case GOTO_EXPR:
case LABEL_EXPR:
case SWITCH_EXPR:
+ case OMP_FOR:
+ case OMP_SECTIONS:
+ case OMP_SECTION:
+ case OMP_SINGLE:
+ case OMP_MASTER:
+ case OMP_ORDERED:
+ case OMP_CRITICAL:
+ case OMP_RETURN:
+ case OMP_CONTINUE:
break;
+ case OMP_PARALLEL:
+ lower_omp_directive (tsi, data);
+ return;
+
default:
-#ifdef ENABLE_CHECKING
- print_node_brief (stderr, "", stmt, 0);
- internal_error ("unexpected node");
-#endif
- case COMPOUND_EXPR:
gcc_unreachable ();
}
return false;
case EH_FILTER_EXPR:
- /* 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,
- we will fall through. We don't know which exceptions may be
- generated, so we just check for EH_FILTER_TYPES being NULL,
- in which case we know that that the exception does not
- match. */
- return (EH_FILTER_TYPES (tsi_stmt (i)) != NULL
- || block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i))));
+ /* 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
return try_catch_may_fallthru (stmt);
case TRY_FINALLY_EXPR:
- return block_may_fallthru (TREE_OPERAND (stmt, 1));
+ /* 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)
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));
default:
return true;
/* Generate a goto statement and remove the return statement. */
found:
- t = build (GOTO_EXPR, void_type_node, label);
+ t = build1 (GOTO_EXPR, void_type_node, label);
SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
tsi_link_before (tsi, t, TSI_SAME_STMT);
tsi_delink (tsi);
}
\f
-/* Record the variables in VARS. */
+/* Record the variables in VARS into function FN. */
void
-record_vars (tree vars)
+record_vars_into (tree vars, tree fn)
{
+ struct function *saved_cfun = cfun;
+
+ if (fn != current_function_decl)
+ cfun = DECL_STRUCT_FUNCTION (fn);
+
for (; vars; vars = TREE_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;
- if (TREE_CODE (var) == FUNCTION_DECL)
- continue;
/* Record the variable. */
cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
cfun->unexpanded_var_list);
}
-}
-
-/* Check whether to expand a variable VAR. */
-
-static bool
-expand_var_p (tree var)
-{
- struct var_ann_d *ann;
-
- if (TREE_CODE (var) != VAR_DECL)
- return true;
-
- /* Leave statics and externals alone. */
- if (TREE_STATIC (var) || DECL_EXTERNAL (var))
- return true;
- /* Remove all unused local variables. */
- ann = var_ann (var);
- if (!ann || !ann->used)
- return false;
-
- return true;
+ if (fn != current_function_decl)
+ cfun = saved_cfun;
}
-/* Throw away variables that are unused. */
-static void
-remove_useless_vars (void)
-{
- tree var, *cell;
- FILE *df = NULL;
+/* Record the variables in VARS into current_function_decl. */
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- df = dump_file;
- fputs ("Discarding as unused:\n", df);
- }
-
- for (cell = &cfun->unexpanded_var_list; *cell; )
- {
- var = TREE_VALUE (*cell);
-
- if (!expand_var_p (var))
- {
- if (df)
- {
- fputs (" ", df);
- print_generic_expr (df, var, dump_flags);
- fputc ('\n', df);
- }
-
- *cell = TREE_CHAIN (*cell);
- continue;
- }
-
- cell = &TREE_CHAIN (*cell);
- }
-
- if (df)
- fputc ('\n', df);
+void
+record_vars (tree vars)
+{
+ record_vars_into (vars, current_function_decl);
}
-struct tree_opt_pass pass_remove_useless_vars =
-{
- "vars", /* name */
- NULL, /* gate */
- remove_useless_vars, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
-};
/* Mark BLOCK used if it has a used variable in it, then recurse over its
subblocks. */
/* Mark the used attribute on blocks correctly. */
-static void
+static unsigned int
mark_used_blocks (void)
{
mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl));
+ return 0;
}